//! SecretumVault KMS Integration Tests //! Tests cover embedded library mode and service mode operations use std::str::FromStr; use vault_service::types::*; use vault_service::KmsService; /// Test configuration for embedded mode (filesystem) #[allow(dead_code)] fn embedded_config() -> KmsBackendConfig { KmsBackendConfig::Secretumvault { server_url: "http://localhost:8200".to_string(), storage_backend: "filesystem".to_string(), auth_token: None, mount_point: "transit".to_string(), key_name: "test-key".to_string(), tls_verify: false, } } /// Test configuration for service mode fn service_config() -> KmsBackendConfig { KmsBackendConfig::Secretumvault { server_url: std::env::var("SECRETUMVAULT_URL") .unwrap_or_else(|_| "http://localhost:8200".to_string()), storage_backend: "surrealdb".to_string(), auth_token: std::env::var("SECRETUMVAULT_TOKEN").ok(), mount_point: "transit".to_string(), key_name: "test-key".to_string(), tls_verify: false, } } #[tokio::test] #[ignore] // Requires SecretumVault service running async fn test_secretumvault_service_health_check() { let config = service_config(); let service = KmsService::new(config) .await .expect("Failed to initialize KMS service"); let health = service.health_check().await.expect("Health check failed"); assert!(health, "SecretumVault service should be healthy"); } #[tokio::test] #[ignore] // Requires SecretumVault service running async fn test_secretumvault_get_version() { let config = service_config(); let service = KmsService::new(config) .await .expect("Failed to initialize KMS service"); let version = service.get_version().await.expect("Failed to get version"); assert!(!version.is_empty(), "Version should not be empty"); println!("SecretumVault version: {}", version); } #[tokio::test] #[ignore] // Requires SecretumVault service running async fn test_secretumvault_encrypt_decrypt() { let config = service_config(); let service = KmsService::new(config) .await .expect("Failed to initialize KMS service"); let plaintext = b"secret data to encrypt"; let context = EncryptionContext::new(); // Encrypt let ciphertext = service .encrypt(plaintext, &context) .await .expect("Encryption failed"); assert!(!ciphertext.is_empty(), "Ciphertext should not be empty"); assert_ne!( plaintext, &ciphertext[..], "Ciphertext should differ from plaintext" ); // Decrypt let decrypted = service .decrypt(&ciphertext, &context) .await .expect("Decryption failed"); assert_eq!( plaintext, &decrypted[..], "Decrypted data should match original plaintext" ); } #[tokio::test] #[ignore] // Requires SecretumVault service running async fn test_secretumvault_encrypt_decrypt_large_data() { let config = service_config(); let service = KmsService::new(config) .await .expect("Failed to initialize KMS service"); // Large data (1 MB) let plaintext = vec![0x42u8; 1024 * 1024]; let context = EncryptionContext::new(); // Encrypt let ciphertext = service .encrypt(&plaintext, &context) .await .expect("Encryption failed"); // Decrypt let decrypted = service .decrypt(&ciphertext, &context) .await .expect("Decryption failed"); assert_eq!( plaintext, decrypted, "Decrypted large data should match original" ); } #[tokio::test] #[ignore] // Requires SecretumVault service running async fn test_secretumvault_encrypt_with_context() { let config = service_config(); let service = KmsService::new(config) .await .expect("Failed to initialize KMS service"); let plaintext = b"sensitive data"; let mut context = EncryptionContext::new(); context.add("environment", "production"); context.add("service", "api-gateway"); // Encrypt with context let ciphertext = service .encrypt(plaintext, &context) .await .expect("Encryption with context failed"); // Decrypt with same context let decrypted = service .decrypt(&ciphertext, &context) .await .expect("Decryption with context failed"); assert_eq!( plaintext, &decrypted[..], "Decrypted data should match original" ); } #[tokio::test] #[ignore] // Requires SecretumVault service running async fn test_secretumvault_generate_aes128_key() { let config = service_config(); let service = KmsService::new(config) .await .expect("Failed to initialize KMS service"); let data_key = service .generate_data_key(&KeySpec::Aes128) .await .expect("Data key generation failed"); assert_eq!( data_key.plaintext.len(), 16, "AES-128 key should be 16 bytes" ); assert!( !data_key.ciphertext.is_empty(), "Encrypted key should not be empty" ); assert_eq!( data_key.key_id, "test-key", "Key ID should match configuration" ); } #[tokio::test] #[ignore] // Requires SecretumVault service running async fn test_secretumvault_generate_aes256_key() { let config = service_config(); let service = KmsService::new(config) .await .expect("Failed to initialize KMS service"); let data_key = service .generate_data_key(&KeySpec::Aes256) .await .expect("Data key generation failed"); assert_eq!( data_key.plaintext.len(), 32, "AES-256 key should be 32 bytes" ); assert!( !data_key.ciphertext.is_empty(), "Encrypted key should not be empty" ); assert_eq!( data_key.key_id, "test-key", "Key ID should match configuration" ); } #[tokio::test] #[ignore] // Requires SecretumVault service running async fn test_secretumvault_generate_rsa2048_key() { let config = service_config(); let service = KmsService::new(config) .await .expect("Failed to initialize KMS service"); let data_key = service .generate_data_key(&KeySpec::Rsa2048) .await .expect("Data key generation failed"); assert_eq!( data_key.plaintext.len(), 256, "RSA-2048 key should be 256 bytes" ); assert!( !data_key.ciphertext.is_empty(), "Encrypted key should not be empty" ); } #[tokio::test] #[ignore] // Requires SecretumVault service running async fn test_secretumvault_generate_rsa4096_key() { let config = service_config(); let service = KmsService::new(config) .await .expect("Failed to initialize KMS service"); let data_key = service .generate_data_key(&KeySpec::Rsa4096) .await .expect("Data key generation failed"); assert_eq!( data_key.plaintext.len(), 512, "RSA-4096 key should be 512 bytes" ); assert!( !data_key.ciphertext.is_empty(), "Encrypted key should not be empty" ); } #[tokio::test] #[ignore] // Requires SecretumVault service running async fn test_secretumvault_multiple_operations() { let config = service_config(); let service = KmsService::new(config) .await .expect("Failed to initialize KMS service"); let context = EncryptionContext::new(); // Perform multiple operations for i in 0..5 { let plaintext = format!("data-{}", i).into_bytes(); let ciphertext = service .encrypt(&plaintext, &context) .await .expect("Encryption failed"); let decrypted = service .decrypt(&ciphertext, &context) .await .expect("Decryption failed"); assert_eq!(plaintext, decrypted, "Data mismatch on iteration {}", i); } // Generate multiple keys for _ in 0..3 { let _key = service .generate_data_key(&KeySpec::Aes256) .await .expect("Key generation failed"); } // Health check after operations let health = service.health_check().await.expect("Health check failed"); assert!(health, "Service should still be healthy"); } #[tokio::test] #[ignore] // Requires SecretumVault service running async fn test_secretumvault_binary_data() { let config = service_config(); let service = KmsService::new(config) .await .expect("Failed to initialize KMS service"); // Binary data with null bytes and special chars let plaintext: Vec = vec![ 0x00, 0x01, 0x02, 0x03, 0xFF, 0xFE, 0xFD, 0xFC, 0x7F, 0x80, 0x00, 0xFF, 0xAB, 0xCD, 0xEF, 0x12, ]; let context = EncryptionContext::new(); let ciphertext = service .encrypt(&plaintext, &context) .await .expect("Binary encryption failed"); let decrypted = service .decrypt(&ciphertext, &context) .await .expect("Binary decryption failed"); assert_eq!( plaintext, decrypted, "Binary data should match after round-trip" ); } #[tokio::test] #[ignore] // Requires SecretumVault service running async fn test_secretumvault_empty_data() { let config = service_config(); let service = KmsService::new(config) .await .expect("Failed to initialize KMS service"); let plaintext: Vec = vec![]; let context = EncryptionContext::new(); // Empty data encryption might be rejected, which is acceptable let result = service.encrypt(&plaintext, &context).await; // Either it succeeds and empty data encrypts, or it fails gracefully if let Ok(ciphertext) = result { let decrypted = service .decrypt(&ciphertext, &context) .await .expect("Empty data decryption failed"); assert!(decrypted.is_empty(), "Decrypted empty data should be empty"); } } #[tokio::test] #[ignore] // Requires SecretumVault service running async fn test_secretumvault_backend_name() { let config = service_config(); let service = KmsService::new(config) .await .expect("Failed to initialize KMS service"); let backend_name = service.get_backend_name(); assert_eq!( backend_name, "secretumvault", "Backend name should be 'secretumvault'" ); } #[tokio::test] #[ignore] // Requires SecretumVault service running async fn test_secretumvault_operations_counter() { let config = service_config(); let service = KmsService::new(config) .await .expect("Failed to initialize KMS service"); let initial_count = service.get_operations_count().await; let context = EncryptionContext::new(); let plaintext = b"test"; // Perform operations let _ = service.encrypt(plaintext, &context).await; let _ = service.health_check().await; let _ = service.get_version().await; let final_count = service.get_operations_count().await; assert!( final_count > initial_count, "Operations counter should increment" ); } #[tokio::test] #[ignore] // Requires SecretumVault service running async fn test_secretumvault_uptime() { let config = service_config(); let service = KmsService::new(config) .await .expect("Failed to initialize KMS service"); // get_uptime() returns u64, always >= 0 by type let _uptime = service.get_uptime(); } #[tokio::test] async fn test_secretumvault_config_validation() { // Invalid storage backend let config = KmsBackendConfig::Secretumvault { server_url: "http://localhost:8200".to_string(), storage_backend: "invalid_backend".to_string(), auth_token: None, mount_point: "transit".to_string(), key_name: "test-key".to_string(), tls_verify: false, }; let result = KmsService::new(config).await; assert!( result.is_err(), "Invalid storage backend should fail validation" ); } #[tokio::test] async fn test_secretumvault_encryption_context_add() { let mut context = EncryptionContext::new(); context.add("key1", "value1"); context.add("key2", "value2"); assert_eq!(context.context.len(), 2, "Context should have 2 entries"); assert_eq!(context.context.get("key1").unwrap(), "value1"); assert_eq!(context.context.get("key2").unwrap(), "value2"); } #[tokio::test] async fn test_secretumvault_encryption_context_from_str() { let context_str = "environment=prod,service=api"; let context = EncryptionContext::from_str(context_str).expect("Failed to parse context"); assert_eq!(context.context.len(), 2); assert_eq!(context.context.get("environment").unwrap(), "prod"); assert_eq!(context.context.get("service").unwrap(), "api"); } #[tokio::test] async fn test_secretumvault_encryption_context_to_string() { let mut context = EncryptionContext::new(); context.add("environment", "prod"); context.add("service", "api"); let context_str = context.to_string(); assert!( !context_str.is_empty(), "Context string should not be empty" ); assert!( context_str.contains("environment=prod"), "Context should include environment" ); assert!( context_str.contains("service=api"), "Context should include service" ); } #[tokio::test] async fn test_key_spec_sizes() { assert_eq!(KeySpec::Aes128.key_size(), 16); assert_eq!(KeySpec::Aes256.key_size(), 32); assert_eq!(KeySpec::Rsa2048.key_size(), 256); assert_eq!(KeySpec::Rsa4096.key_size(), 512); } // Integration test runner helper - run with: // cargo test --package vault-service --test secretumvault_integration -- // --ignored --test-threads=1 // // Before running tests, start SecretumVault: // secretumvault server --storage-backend filesystem // // Optional: set environment variables for service mode tests: // export SECRETUMVAULT_URL=http://localhost:8200 // export SECRETUMVAULT_TOKEN=your-token