645 lines
17 KiB
Rust
645 lines
17 KiB
Rust
|
|
//! Comprehensive tests for audit logging system
|
||
|
|
//!
|
||
|
|
//! Tests audit logger, storage, queries, exports, and GDPR compliance.
|
||
|
|
//!
|
||
|
|
//! NOTE: These tests are disabled due to API mismatches
|
||
|
|
//! (log_success/log_failure signature changes)
|
||
|
|
|
||
|
|
// Disabled: API mismatches
|
||
|
|
#![allow(unexpected_cfgs)]
|
||
|
|
#![cfg(feature = "audit_logging_tests")]
|
||
|
|
#![allow(unused_imports, clippy::single_component_path_imports)]
|
||
|
|
|
||
|
|
use std::collections::HashMap;
|
||
|
|
use std::sync::Arc;
|
||
|
|
|
||
|
|
use provisioning_orchestrator::audit::{
|
||
|
|
ActionInfo, ActionType, AuditEvent, AuditFilter, AuditLogger, AuditLoggerConfig, AuditQuery,
|
||
|
|
AuditStatus, AuthorizationInfo, FileStorage, RetentionPolicy, SiemFormat, UserInfo,
|
||
|
|
};
|
||
|
|
use tempfile::TempDir;
|
||
|
|
use tokio;
|
||
|
|
|
||
|
|
/// Helper: Create test user
|
||
|
|
fn create_test_user(id: &str) -> UserInfo {
|
||
|
|
UserInfo {
|
||
|
|
id: id.to_string(),
|
||
|
|
name: format!("User {}", id),
|
||
|
|
ip: "192.168.1.100".to_string(),
|
||
|
|
user_agent: "TestAgent/1.0".to_string(),
|
||
|
|
email: Some(format!("{}@example.com", id)),
|
||
|
|
session_id: Some(format!("session_{}", id)),
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/// Helper: Create test action
|
||
|
|
fn create_test_action(action_type: ActionType, resource: &str) -> ActionInfo {
|
||
|
|
ActionInfo {
|
||
|
|
action_type,
|
||
|
|
resource: resource.to_string(),
|
||
|
|
workspace: "test-workspace".to_string(),
|
||
|
|
parameters: serde_json::json!({"test": "data"}),
|
||
|
|
tags: HashMap::new(),
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/// Helper: Create test authorization
|
||
|
|
fn create_test_authz(mfa: bool) -> AuthorizationInfo {
|
||
|
|
AuthorizationInfo {
|
||
|
|
token_id: "test_token_123".to_string(),
|
||
|
|
cedar_policy: "policy::allow_all".to_string(),
|
||
|
|
mfa_verified: mfa,
|
||
|
|
permissions: vec!["*:*".to_string()],
|
||
|
|
evaluation_duration_us: Some(150),
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/// Helper: Create test logger
|
||
|
|
async fn create_test_logger() -> (Arc<AuditLogger>, TempDir) {
|
||
|
|
let temp_dir = TempDir::new().unwrap();
|
||
|
|
let storage = Arc::new(
|
||
|
|
FileStorage::new(temp_dir.path().to_path_buf(), 10 * 1024 * 1024)
|
||
|
|
.await
|
||
|
|
.unwrap(),
|
||
|
|
);
|
||
|
|
|
||
|
|
let config = AuditLoggerConfig {
|
||
|
|
enabled: true,
|
||
|
|
anonymize_pii: false,
|
||
|
|
buffer_size: 10,
|
||
|
|
flush_interval_secs: 60, // Long interval for manual flushing in tests
|
||
|
|
retention_policy: RetentionPolicy::default(),
|
||
|
|
debug: false,
|
||
|
|
};
|
||
|
|
|
||
|
|
let logger = Arc::new(AuditLogger::new(config, storage).await.unwrap());
|
||
|
|
(logger, temp_dir)
|
||
|
|
}
|
||
|
|
|
||
|
|
#[tokio::test]
|
||
|
|
async fn test_audit_logger_initialization() {
|
||
|
|
let (logger, _temp) = create_test_logger().await;
|
||
|
|
|
||
|
|
let stats = logger.stats().await;
|
||
|
|
assert_eq!(stats.total_events, 0);
|
||
|
|
assert_eq!(stats.buffered_events, 0);
|
||
|
|
}
|
||
|
|
|
||
|
|
#[tokio::test]
|
||
|
|
async fn test_log_single_event() {
|
||
|
|
let (logger, _temp) = create_test_logger().await;
|
||
|
|
|
||
|
|
let user = create_test_user("user1");
|
||
|
|
let action = create_test_action(ActionType::ServerCreate, "server-01");
|
||
|
|
let authz = create_test_authz(true);
|
||
|
|
|
||
|
|
let event = AuditEvent::new(user, action, authz).complete(150);
|
||
|
|
logger.log(event).await.unwrap();
|
||
|
|
|
||
|
|
let stats = logger.stats().await;
|
||
|
|
assert_eq!(stats.total_events, 1);
|
||
|
|
assert_eq!(stats.success_events, 1);
|
||
|
|
assert_eq!(stats.buffered_events, 1);
|
||
|
|
}
|
||
|
|
|
||
|
|
#[tokio::test]
|
||
|
|
async fn test_log_success_convenience_method() {
|
||
|
|
let (logger, _temp) = create_test_logger().await;
|
||
|
|
|
||
|
|
logger
|
||
|
|
.log_success(
|
||
|
|
create_test_user("user2"),
|
||
|
|
ActionType::TaskservCreate,
|
||
|
|
"kubernetes".to_string(),
|
||
|
|
"production".to_string(),
|
||
|
|
serde_json::json!({"version": "1.28.0"}),
|
||
|
|
create_test_authz(false),
|
||
|
|
250,
|
||
|
|
)
|
||
|
|
.await
|
||
|
|
.unwrap();
|
||
|
|
|
||
|
|
let stats = logger.stats().await;
|
||
|
|
assert_eq!(stats.total_events, 1);
|
||
|
|
assert_eq!(stats.success_events, 1);
|
||
|
|
}
|
||
|
|
|
||
|
|
#[tokio::test]
|
||
|
|
async fn test_log_failure_convenience_method() {
|
||
|
|
let (logger, _temp) = create_test_logger().await;
|
||
|
|
|
||
|
|
logger
|
||
|
|
.log_failure(
|
||
|
|
create_test_user("user3"),
|
||
|
|
ActionType::ClusterCreate,
|
||
|
|
"cluster-01".to_string(),
|
||
|
|
"staging".to_string(),
|
||
|
|
serde_json::json!({}),
|
||
|
|
create_test_authz(true),
|
||
|
|
500,
|
||
|
|
"Insufficient permissions".to_string(),
|
||
|
|
)
|
||
|
|
.await
|
||
|
|
.unwrap();
|
||
|
|
|
||
|
|
let stats = logger.stats().await;
|
||
|
|
assert_eq!(stats.total_events, 1);
|
||
|
|
assert_eq!(stats.failure_events, 1);
|
||
|
|
}
|
||
|
|
|
||
|
|
#[tokio::test]
|
||
|
|
async fn test_buffer_and_flush() {
|
||
|
|
let (logger, _temp) = create_test_logger().await;
|
||
|
|
|
||
|
|
// Log multiple events
|
||
|
|
for i in 0..5 {
|
||
|
|
logger
|
||
|
|
.log_success(
|
||
|
|
create_test_user(&format!("user{}", i)),
|
||
|
|
ActionType::ServerList,
|
||
|
|
"*".to_string(),
|
||
|
|
"test".to_string(),
|
||
|
|
serde_json::json!({}),
|
||
|
|
create_test_authz(false),
|
||
|
|
50,
|
||
|
|
)
|
||
|
|
.await
|
||
|
|
.unwrap();
|
||
|
|
}
|
||
|
|
|
||
|
|
let stats_before = logger.stats().await;
|
||
|
|
assert_eq!(stats_before.buffered_events, 5);
|
||
|
|
assert_eq!(stats_before.flushed_events, 0);
|
||
|
|
|
||
|
|
// Flush
|
||
|
|
logger.flush().await.unwrap();
|
||
|
|
|
||
|
|
let stats_after = logger.stats().await;
|
||
|
|
assert_eq!(stats_after.buffered_events, 0);
|
||
|
|
assert_eq!(stats_after.flushed_events, 5);
|
||
|
|
}
|
||
|
|
|
||
|
|
#[tokio::test]
|
||
|
|
async fn test_query_all_events() {
|
||
|
|
let (logger, _temp) = create_test_logger().await;
|
||
|
|
|
||
|
|
// Log and flush
|
||
|
|
for i in 0..3 {
|
||
|
|
logger
|
||
|
|
.log_success(
|
||
|
|
create_test_user(&format!("user{}", i)),
|
||
|
|
ActionType::ServerCreate,
|
||
|
|
format!("server-{}", i),
|
||
|
|
"test".to_string(),
|
||
|
|
serde_json::json!({}),
|
||
|
|
create_test_authz(true),
|
||
|
|
100,
|
||
|
|
)
|
||
|
|
.await
|
||
|
|
.unwrap();
|
||
|
|
}
|
||
|
|
|
||
|
|
logger.flush().await.unwrap();
|
||
|
|
|
||
|
|
// Query all
|
||
|
|
let query = AuditQuery::default();
|
||
|
|
let events = logger.query(query).await.unwrap();
|
||
|
|
|
||
|
|
assert_eq!(events.len(), 3);
|
||
|
|
}
|
||
|
|
|
||
|
|
#[tokio::test]
|
||
|
|
async fn test_query_filter_by_user() {
|
||
|
|
let (logger, _temp) = create_test_logger().await;
|
||
|
|
|
||
|
|
// Log events from different users
|
||
|
|
logger
|
||
|
|
.log_success(
|
||
|
|
create_test_user("alice"),
|
||
|
|
ActionType::ServerCreate,
|
||
|
|
"server-01".to_string(),
|
||
|
|
"test".to_string(),
|
||
|
|
serde_json::json!({}),
|
||
|
|
create_test_authz(true),
|
||
|
|
100,
|
||
|
|
)
|
||
|
|
.await
|
||
|
|
.unwrap();
|
||
|
|
|
||
|
|
logger
|
||
|
|
.log_success(
|
||
|
|
create_test_user("bob"),
|
||
|
|
ActionType::ServerCreate,
|
||
|
|
"server-02".to_string(),
|
||
|
|
"test".to_string(),
|
||
|
|
serde_json::json!({}),
|
||
|
|
create_test_authz(true),
|
||
|
|
100,
|
||
|
|
)
|
||
|
|
.await
|
||
|
|
.unwrap();
|
||
|
|
|
||
|
|
logger.flush().await.unwrap();
|
||
|
|
|
||
|
|
// Query for alice only
|
||
|
|
let query = AuditQuery {
|
||
|
|
filter: AuditFilter {
|
||
|
|
user_id: Some("alice".to_string()),
|
||
|
|
..Default::default()
|
||
|
|
},
|
||
|
|
..Default::default()
|
||
|
|
};
|
||
|
|
|
||
|
|
let events = logger.query(query).await.unwrap();
|
||
|
|
assert_eq!(events.len(), 1);
|
||
|
|
assert_eq!(events[0].user.id, "alice");
|
||
|
|
}
|
||
|
|
|
||
|
|
#[tokio::test]
|
||
|
|
async fn test_query_filter_by_action_type() {
|
||
|
|
let (logger, _temp) = create_test_logger().await;
|
||
|
|
|
||
|
|
// Log different action types
|
||
|
|
logger
|
||
|
|
.log_success(
|
||
|
|
create_test_user("user1"),
|
||
|
|
ActionType::ServerCreate,
|
||
|
|
"server-01".to_string(),
|
||
|
|
"test".to_string(),
|
||
|
|
serde_json::json!({}),
|
||
|
|
create_test_authz(true),
|
||
|
|
100,
|
||
|
|
)
|
||
|
|
.await
|
||
|
|
.unwrap();
|
||
|
|
|
||
|
|
logger
|
||
|
|
.log_success(
|
||
|
|
create_test_user("user1"),
|
||
|
|
ActionType::TaskservCreate,
|
||
|
|
"kubernetes".to_string(),
|
||
|
|
"test".to_string(),
|
||
|
|
serde_json::json!({}),
|
||
|
|
create_test_authz(true),
|
||
|
|
150,
|
||
|
|
)
|
||
|
|
.await
|
||
|
|
.unwrap();
|
||
|
|
|
||
|
|
logger.flush().await.unwrap();
|
||
|
|
|
||
|
|
// Query for TaskservCreate only
|
||
|
|
let query = AuditQuery {
|
||
|
|
filter: AuditFilter {
|
||
|
|
action_type: Some(ActionType::TaskservCreate),
|
||
|
|
..Default::default()
|
||
|
|
},
|
||
|
|
..Default::default()
|
||
|
|
};
|
||
|
|
|
||
|
|
let events = logger.query(query).await.unwrap();
|
||
|
|
assert_eq!(events.len(), 1);
|
||
|
|
assert_eq!(events[0].action.action_type, ActionType::TaskservCreate);
|
||
|
|
}
|
||
|
|
|
||
|
|
#[tokio::test]
|
||
|
|
async fn test_query_filter_by_status() {
|
||
|
|
let (logger, _temp) = create_test_logger().await;
|
||
|
|
|
||
|
|
// Log success and failure
|
||
|
|
logger
|
||
|
|
.log_success(
|
||
|
|
create_test_user("user1"),
|
||
|
|
ActionType::ServerCreate,
|
||
|
|
"server-01".to_string(),
|
||
|
|
"test".to_string(),
|
||
|
|
serde_json::json!({}),
|
||
|
|
create_test_authz(true),
|
||
|
|
100,
|
||
|
|
)
|
||
|
|
.await
|
||
|
|
.unwrap();
|
||
|
|
|
||
|
|
logger
|
||
|
|
.log_failure(
|
||
|
|
create_test_user("user1"),
|
||
|
|
ActionType::ServerCreate,
|
||
|
|
"server-02".to_string(),
|
||
|
|
"test".to_string(),
|
||
|
|
serde_json::json!({}),
|
||
|
|
create_test_authz(true),
|
||
|
|
200,
|
||
|
|
"Permission denied".to_string(),
|
||
|
|
)
|
||
|
|
.await
|
||
|
|
.unwrap();
|
||
|
|
|
||
|
|
logger.flush().await.unwrap();
|
||
|
|
|
||
|
|
// Query for failures only
|
||
|
|
let query = AuditQuery {
|
||
|
|
filter: AuditFilter {
|
||
|
|
status: Some(AuditStatus::Failure),
|
||
|
|
..Default::default()
|
||
|
|
},
|
||
|
|
..Default::default()
|
||
|
|
};
|
||
|
|
|
||
|
|
let events = logger.query(query).await.unwrap();
|
||
|
|
assert_eq!(events.len(), 1);
|
||
|
|
assert_eq!(events[0].result.status, AuditStatus::Failure);
|
||
|
|
}
|
||
|
|
|
||
|
|
#[tokio::test]
|
||
|
|
async fn test_query_with_limit() {
|
||
|
|
let (logger, _temp) = create_test_logger().await;
|
||
|
|
|
||
|
|
// Log 10 events
|
||
|
|
for i in 0..10 {
|
||
|
|
logger
|
||
|
|
.log_success(
|
||
|
|
create_test_user(&format!("user{}", i)),
|
||
|
|
ActionType::ServerList,
|
||
|
|
"*".to_string(),
|
||
|
|
"test".to_string(),
|
||
|
|
serde_json::json!({}),
|
||
|
|
create_test_authz(false),
|
||
|
|
50,
|
||
|
|
)
|
||
|
|
.await
|
||
|
|
.unwrap();
|
||
|
|
}
|
||
|
|
|
||
|
|
logger.flush().await.unwrap();
|
||
|
|
|
||
|
|
// Query with limit
|
||
|
|
let query = AuditQuery {
|
||
|
|
filter: AuditFilter::default(),
|
||
|
|
limit: Some(5),
|
||
|
|
offset: None,
|
||
|
|
sort_by: None,
|
||
|
|
sort_desc: false,
|
||
|
|
};
|
||
|
|
|
||
|
|
let events = logger.query(query).await.unwrap();
|
||
|
|
assert_eq!(events.len(), 5);
|
||
|
|
}
|
||
|
|
|
||
|
|
#[tokio::test]
|
||
|
|
async fn test_export_json() {
|
||
|
|
let (logger, _temp) = create_test_logger().await;
|
||
|
|
|
||
|
|
logger
|
||
|
|
.log_success(
|
||
|
|
create_test_user("user1"),
|
||
|
|
ActionType::ServerCreate,
|
||
|
|
"server-01".to_string(),
|
||
|
|
"test".to_string(),
|
||
|
|
serde_json::json!({}),
|
||
|
|
create_test_authz(true),
|
||
|
|
100,
|
||
|
|
)
|
||
|
|
.await
|
||
|
|
.unwrap();
|
||
|
|
|
||
|
|
logger.flush().await.unwrap();
|
||
|
|
|
||
|
|
// Export as JSON
|
||
|
|
let exported = logger.export(SiemFormat::Json, None).await.unwrap();
|
||
|
|
let json_str = String::from_utf8(exported).unwrap();
|
||
|
|
|
||
|
|
assert!(json_str.contains("server-01"));
|
||
|
|
assert!(json_str.contains("user1"));
|
||
|
|
}
|
||
|
|
|
||
|
|
#[tokio::test]
|
||
|
|
async fn test_export_csv() {
|
||
|
|
let (logger, _temp) = create_test_logger().await;
|
||
|
|
|
||
|
|
logger
|
||
|
|
.log_success(
|
||
|
|
create_test_user("user1"),
|
||
|
|
ActionType::ServerCreate,
|
||
|
|
"server-01".to_string(),
|
||
|
|
"test".to_string(),
|
||
|
|
serde_json::json!({}),
|
||
|
|
create_test_authz(true),
|
||
|
|
100,
|
||
|
|
)
|
||
|
|
.await
|
||
|
|
.unwrap();
|
||
|
|
|
||
|
|
logger.flush().await.unwrap();
|
||
|
|
|
||
|
|
// Export as CSV
|
||
|
|
let exported = logger.export(SiemFormat::Csv, None).await.unwrap();
|
||
|
|
let csv_str = String::from_utf8(exported).unwrap();
|
||
|
|
|
||
|
|
assert!(csv_str.contains("event_id,timestamp"));
|
||
|
|
assert!(csv_str.contains("user1"));
|
||
|
|
assert!(csv_str.contains("server-01"));
|
||
|
|
}
|
||
|
|
|
||
|
|
#[tokio::test]
|
||
|
|
async fn test_pii_anonymization() {
|
||
|
|
let temp_dir = TempDir::new().unwrap();
|
||
|
|
let storage = Arc::new(
|
||
|
|
FileStorage::new(temp_dir.path().to_path_buf(), 10 * 1024 * 1024)
|
||
|
|
.await
|
||
|
|
.unwrap(),
|
||
|
|
);
|
||
|
|
|
||
|
|
let config = AuditLoggerConfig {
|
||
|
|
enabled: true,
|
||
|
|
anonymize_pii: true, // Enable PII anonymization
|
||
|
|
buffer_size: 10,
|
||
|
|
flush_interval_secs: 60,
|
||
|
|
retention_policy: RetentionPolicy::default(),
|
||
|
|
debug: false,
|
||
|
|
};
|
||
|
|
|
||
|
|
let logger = Arc::new(AuditLogger::new(config, storage).await.unwrap());
|
||
|
|
|
||
|
|
// Log event with PII
|
||
|
|
logger
|
||
|
|
.log_success(
|
||
|
|
create_test_user("john_doe"),
|
||
|
|
ActionType::ConfigRead,
|
||
|
|
"config.toml".to_string(),
|
||
|
|
"test".to_string(),
|
||
|
|
serde_json::json!({}),
|
||
|
|
create_test_authz(true),
|
||
|
|
50,
|
||
|
|
)
|
||
|
|
.await
|
||
|
|
.unwrap();
|
||
|
|
|
||
|
|
logger.flush().await.unwrap();
|
||
|
|
|
||
|
|
// Query and verify anonymization
|
||
|
|
let query = AuditQuery::default();
|
||
|
|
let events = logger.query(query).await.unwrap();
|
||
|
|
|
||
|
|
assert_eq!(events.len(), 1);
|
||
|
|
assert!(events[0].user.id.starts_with("hashed_"));
|
||
|
|
assert_eq!(events[0].user.email, None);
|
||
|
|
assert_ne!(events[0].user.name, "User john_doe");
|
||
|
|
}
|
||
|
|
|
||
|
|
#[tokio::test]
|
||
|
|
async fn test_kms_access_tracking() {
|
||
|
|
let (logger, _temp) = create_test_logger().await;
|
||
|
|
|
||
|
|
let user = create_test_user("user1");
|
||
|
|
let action = create_test_action(ActionType::SecretRead, "database-password");
|
||
|
|
let authz = create_test_authz(true);
|
||
|
|
|
||
|
|
let event = AuditEvent::new(user, action, authz)
|
||
|
|
.add_kms_access("kms-key-12345".to_string())
|
||
|
|
.add_kms_access("kms-key-67890".to_string())
|
||
|
|
.complete(100);
|
||
|
|
|
||
|
|
logger.log(event).await.unwrap();
|
||
|
|
logger.flush().await.unwrap();
|
||
|
|
|
||
|
|
// Query and verify KMS access records
|
||
|
|
let query = AuditQuery::default();
|
||
|
|
let events = logger.query(query).await.unwrap();
|
||
|
|
|
||
|
|
assert_eq!(events.len(), 1);
|
||
|
|
assert_eq!(events[0].kms_access.len(), 2);
|
||
|
|
assert_eq!(events[0].kms_access[0].key, "kms-key-12345");
|
||
|
|
assert_eq!(events[0].kms_access[1].key, "kms-key-67890");
|
||
|
|
}
|
||
|
|
|
||
|
|
#[tokio::test]
|
||
|
|
async fn test_metadata_tracking() {
|
||
|
|
let (logger, _temp) = create_test_logger().await;
|
||
|
|
|
||
|
|
let user = create_test_user("user1");
|
||
|
|
let action = create_test_action(ActionType::ServerCreate, "server-01");
|
||
|
|
let authz = create_test_authz(true);
|
||
|
|
|
||
|
|
let event = AuditEvent::new(user, action, authz)
|
||
|
|
.add_metadata("region".to_string(), "us-east-1".to_string())
|
||
|
|
.add_metadata("provider".to_string(), "aws".to_string())
|
||
|
|
.complete(150);
|
||
|
|
|
||
|
|
logger.log(event).await.unwrap();
|
||
|
|
logger.flush().await.unwrap();
|
||
|
|
|
||
|
|
// Query and verify metadata
|
||
|
|
let query = AuditQuery::default();
|
||
|
|
let events = logger.query(query).await.unwrap();
|
||
|
|
|
||
|
|
assert_eq!(events.len(), 1);
|
||
|
|
assert_eq!(events[0].metadata.get("region").unwrap(), "us-east-1");
|
||
|
|
assert_eq!(events[0].metadata.get("provider").unwrap(), "aws");
|
||
|
|
}
|
||
|
|
|
||
|
|
#[tokio::test]
|
||
|
|
async fn test_retention_policy() {
|
||
|
|
// Note: This test would require mocking time or waiting
|
||
|
|
// For now, we just verify the retention policy can be applied
|
||
|
|
let (logger, _temp) = create_test_logger().await;
|
||
|
|
|
||
|
|
// Log some events
|
||
|
|
logger
|
||
|
|
.log_success(
|
||
|
|
create_test_user("user1"),
|
||
|
|
ActionType::ServerList,
|
||
|
|
"*".to_string(),
|
||
|
|
"test".to_string(),
|
||
|
|
serde_json::json!({}),
|
||
|
|
create_test_authz(false),
|
||
|
|
50,
|
||
|
|
)
|
||
|
|
.await
|
||
|
|
.unwrap();
|
||
|
|
|
||
|
|
logger.flush().await.unwrap();
|
||
|
|
|
||
|
|
// Apply retention (should not delete anything as events are fresh)
|
||
|
|
let deleted = logger.apply_retention().await.unwrap();
|
||
|
|
assert_eq!(deleted, 0);
|
||
|
|
}
|
||
|
|
|
||
|
|
#[tokio::test]
|
||
|
|
async fn test_concurrent_logging() {
|
||
|
|
let (logger, _temp) = create_test_logger().await;
|
||
|
|
|
||
|
|
// Log events concurrently
|
||
|
|
let mut handles = vec![];
|
||
|
|
for i in 0..10 {
|
||
|
|
let logger_clone = logger.clone();
|
||
|
|
let handle = tokio::spawn(async move {
|
||
|
|
logger_clone
|
||
|
|
.log_success(
|
||
|
|
create_test_user(&format!("user{}", i)),
|
||
|
|
ActionType::ServerList,
|
||
|
|
"*".to_string(),
|
||
|
|
"test".to_string(),
|
||
|
|
serde_json::json!({}),
|
||
|
|
create_test_authz(false),
|
||
|
|
50,
|
||
|
|
)
|
||
|
|
.await
|
||
|
|
.unwrap();
|
||
|
|
});
|
||
|
|
handles.push(handle);
|
||
|
|
}
|
||
|
|
|
||
|
|
// Wait for all tasks
|
||
|
|
for handle in handles {
|
||
|
|
handle.await.unwrap();
|
||
|
|
}
|
||
|
|
|
||
|
|
let stats = logger.stats().await;
|
||
|
|
assert_eq!(stats.total_events, 10);
|
||
|
|
}
|
||
|
|
|
||
|
|
#[tokio::test]
|
||
|
|
async fn test_statistics_accuracy() {
|
||
|
|
let (logger, _temp) = create_test_logger().await;
|
||
|
|
|
||
|
|
// Log mixed events
|
||
|
|
logger
|
||
|
|
.log_success(
|
||
|
|
create_test_user("user1"),
|
||
|
|
ActionType::ServerCreate,
|
||
|
|
"server-01".to_string(),
|
||
|
|
"test".to_string(),
|
||
|
|
serde_json::json!({}),
|
||
|
|
create_test_authz(true),
|
||
|
|
100,
|
||
|
|
)
|
||
|
|
.await
|
||
|
|
.unwrap();
|
||
|
|
|
||
|
|
logger
|
||
|
|
.log_failure(
|
||
|
|
create_test_user("user2"),
|
||
|
|
ActionType::ServerCreate,
|
||
|
|
"server-02".to_string(),
|
||
|
|
"test".to_string(),
|
||
|
|
serde_json::json!({}),
|
||
|
|
create_test_authz(true),
|
||
|
|
150,
|
||
|
|
"Error".to_string(),
|
||
|
|
)
|
||
|
|
.await
|
||
|
|
.unwrap();
|
||
|
|
|
||
|
|
let user = create_test_user("user3");
|
||
|
|
let action = create_test_action(ActionType::ServerCreate, "server-03");
|
||
|
|
let authz = create_test_authz(true);
|
||
|
|
let error_event = AuditEvent::new(user, action, authz).error(200, "Critical error".to_string());
|
||
|
|
logger.log(error_event).await.unwrap();
|
||
|
|
|
||
|
|
let stats = logger.stats().await;
|
||
|
|
assert_eq!(stats.total_events, 3);
|
||
|
|
assert_eq!(stats.success_events, 1);
|
||
|
|
assert_eq!(stats.failure_events, 1);
|
||
|
|
assert_eq!(stats.error_events, 1);
|
||
|
|
}
|