use rustfs_audit::*;
use std::sync::Arc;
use std::time::{Duration, Instant};
use tokio::time::timeout;
#[tokio::test]
async fn test_audit_system_startup_performance() {
let system = AuditSystem::new();
let start = Instant::now();
let config = rustfs_config::server_config::Config(std::collections::HashMap::new());
let _result = timeout(Duration::from_secs(5), system.start(config)).await;
let elapsed = start.elapsed();
println!("Audit system startup took: {elapsed:?}");
assert!(elapsed < Duration::from_secs(5), "Startup took too long: {elapsed:?}");
let _ = system.close().await;
}
#[tokio::test]
async fn test_concurrent_target_creation() {
let registry = AuditRegistry::new();
let mut config = rustfs_config::server_config::Config(std::collections::HashMap::new());
let mut webhook_section = std::collections::HashMap::new();
for i in 1..=5 {
let mut kvs = rustfs_config::server_config::KVS::new();
kvs.insert("enable".to_string(), "on".to_string());
kvs.insert("endpoint".to_string(), format!("http://localhost:302{i}/webhook"));
webhook_section.insert(format!("instance_{i}"), kvs);
}
config.0.insert("audit_webhook".to_string(), webhook_section);
let start = Instant::now();
let result = registry.create_audit_targets_from_config(&config).await;
let elapsed = start.elapsed();
println!("Concurrent target creation took: {elapsed:?}");
assert!(elapsed < Duration::from_secs(10), "Target creation took too long: {elapsed:?}");
match result {
Err(AuditError::StorageNotAvailable(_)) => {
}
Err(e) => {
println!("Unexpected error during concurrent creation: {e}");
}
Ok(_) => {
println!("Unexpected success in test environment");
}
}
}
#[tokio::test]
async fn test_audit_log_dispatch_performance() {
let system = AuditSystem::new();
let config = rustfs_config::server_config::Config(HashMap::new());
let start_result = system.start(config).await;
if start_result.is_err() {
println!("AuditSystem failed to start: {start_result:?}");
return; }
use jiff::Timestamp;
use rustfs_targets::EventName;
use serde_json::json;
use std::collections::HashMap;
let id = 1;
let mut req_header = hashbrown::HashMap::new();
req_header.insert("authorization".to_string(), format!("Bearer test-token-{id}"));
req_header.insert("content-type".to_string(), "application/octet-stream".to_string());
let mut resp_header = hashbrown::HashMap::new();
resp_header.insert("x-response".to_string(), "ok".to_string());
let mut tags = hashbrown::HashMap::new();
tags.insert(format!("tag-{id}"), json!("sample"));
let mut req_query = hashbrown::HashMap::new();
req_query.insert("id".to_string(), id.to_string());
let api_details = ApiDetails {
name: Some("PutObject".to_string()),
bucket: Some("test-bucket".to_string()),
object: Some(format!("test-object-{id}")),
status: Some("success".to_string()),
status_code: Some(200),
input_bytes: Some(1024),
output_bytes: Some(0),
header_bytes: Some(128),
time_to_first_byte: Some("1ms".to_string()),
time_to_first_byte_in_ns: Some("1000000".to_string()),
time_to_response: Some("2ms".to_string()),
time_to_response_in_ns: Some("2000000".to_string()),
..Default::default()
};
let audit_entry = AuditEntry {
version: "1".to_string(),
deployment_id: Some(format!("test-deployment-{id}")),
site_name: Some("test-site".to_string()),
time: Timestamp::now(),
event: EventName::ObjectCreatedPut,
entry_type: Some("object".to_string()),
trigger: "api".to_string(),
api: api_details,
remote_host: Some("127.0.0.1".to_string()),
request_id: Some(format!("test-request-{id}")),
user_agent: Some("test-agent".to_string()),
req_path: Some(format!("/test-bucket/test-object-{id}")),
req_host: Some("test-host".to_string()),
req_node: Some("node-1".to_string()),
req_claims: None,
req_query: Some(req_query),
req_header: Some(req_header),
resp_header: Some(resp_header),
tags: Some(tags),
access_key: Some(format!("AKIA{id}")),
parent_user: Some(format!("parent-{id}")),
error: None,
};
let start = Instant::now();
let result = system.dispatch(Arc::new(audit_entry)).await;
let elapsed = start.elapsed();
println!("Audit log dispatch took: {elapsed:?}");
assert!(elapsed < Duration::from_millis(100), "Dispatch took too long: {elapsed:?}");
assert!(
matches!(result, Err(AuditError::NotInitialized(_))),
"Dispatch on a stopped system should return NotInitialized, got: {result:?}"
);
let _ = system.close().await;
}
#[tokio::test]
async fn test_system_state_transitions() {
let system = AuditSystem::new();
assert_eq!(system.get_state().await, rustfs_audit::system::AuditSystemState::Stopped);
let config = rustfs_config::server_config::Config(std::collections::HashMap::new());
let start_result = system.start(config).await;
let state = system.get_state().await;
match start_result {
Ok(_) => {
assert_eq!(state, rustfs_audit::system::AuditSystemState::Stopped);
}
Err(_) => {
assert_eq!(state, rustfs_audit::system::AuditSystemState::Stopped);
}
}
let _ = system.close().await;
assert_eq!(system.get_state().await, rustfs_audit::system::AuditSystemState::Stopped);
}
#[test]
fn test_event_name_mask_performance() {
use rustfs_targets::EventName;
let events = vec![
EventName::ObjectCreatedPut,
EventName::ObjectAccessedGet,
EventName::ObjectRemovedDelete,
EventName::ObjectCreatedAll,
EventName::Everything,
];
let start = Instant::now();
for _ in 0..1000 {
for event in &events {
let _mask = event.mask();
}
}
let elapsed = start.elapsed();
println!("Event mask calculation (5000 ops) took: {elapsed:?}");
assert!(elapsed < Duration::from_millis(100), "Mask calculation too slow: {elapsed:?}");
}
#[test]
fn test_event_name_expansion_performance() {
use rustfs_targets::EventName;
let compound_events = vec![
EventName::ObjectCreatedAll,
EventName::ObjectAccessedAll,
EventName::ObjectRemovedAll,
EventName::Everything,
];
let start = Instant::now();
for _ in 0..1000 {
for event in &compound_events {
let _expanded = event.expand();
}
}
let elapsed = start.elapsed();
println!("Event expansion (4000 ops) took: {elapsed:?}");
assert!(elapsed < Duration::from_millis(100), "Expansion too slow: {elapsed:?}");
}
#[tokio::test]
async fn test_registry_operations_performance() {
let registry = AuditRegistry::new();
let start = Instant::now();
for _ in 0..1000 {
let targets = registry.list_targets();
let _target = registry.get_target("nonexistent");
assert!(targets.is_empty());
}
let elapsed = start.elapsed();
println!("Registry operations (2000 ops) took: {elapsed:?}");
assert!(elapsed < Duration::from_millis(100), "Registry ops too slow: {elapsed:?}");
}
#[test]
fn test_performance_requirements() {
let start = Instant::now();
for i in 0..3000 {
let _event_id = format!("s3:ObjectCreated:Put_{i}");
let _timestamp = jiff::Timestamp::now().to_string();
let _entry_size = 512; let _processing_time = std::time::Duration::from_nanos(100); }
let elapsed = start.elapsed();
let eps = 3000.0 / elapsed.as_secs_f64();
println!("Simulated 3000 events in {elapsed:?} ({eps:.0} EPS)");
assert!(eps > 10000.0, "Core processing too slow for 3k EPS target: {eps} EPS");
let avg_latency = elapsed / 3000;
println!("Average processing latency: {avg_latency:?}");
assert!(avg_latency < Duration::from_millis(1), "Processing latency too high: {avg_latency:?}");
}