use super::event::AuditEvent;
use anyhow::Result;
use async_trait::async_trait;
#[async_trait]
pub trait AuditExporter: Send + Sync {
async fn export(&self, event: AuditEvent) -> Result<()>;
async fn export_batch(&self, events: &[AuditEvent]) -> Result<()> {
for event in events {
self.export(event.clone()).await?;
}
Ok(())
}
async fn flush(&self) -> Result<()>;
async fn close(&self) -> Result<()>;
}
#[derive(Debug, Clone, Default)]
pub struct NullExporter;
impl NullExporter {
pub fn new() -> Self {
Self
}
}
#[async_trait]
impl AuditExporter for NullExporter {
async fn export(&self, _event: AuditEvent) -> Result<()> {
Ok(())
}
async fn export_batch(&self, _events: &[AuditEvent]) -> Result<()> {
Ok(())
}
async fn flush(&self) -> Result<()> {
Ok(())
}
async fn close(&self) -> Result<()> {
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::server::audit::event::{EventResult, EventType};
#[tokio::test]
async fn test_null_exporter_export() {
let exporter = NullExporter::new();
let event = AuditEvent::new(
EventType::AuthSuccess,
"test".to_string(),
"session-1".to_string(),
);
let result = exporter.export(event).await;
assert!(result.is_ok());
}
#[tokio::test]
async fn test_null_exporter_batch() {
let exporter = NullExporter::new();
let events = vec![
AuditEvent::new(
EventType::AuthSuccess,
"user1".to_string(),
"session-1".to_string(),
),
AuditEvent::new(
EventType::AuthFailure,
"user2".to_string(),
"session-2".to_string(),
)
.with_result(EventResult::Failure),
];
let result = exporter.export_batch(&events).await;
assert!(result.is_ok());
}
#[tokio::test]
async fn test_null_exporter_flush() {
let exporter = NullExporter::new();
let result = exporter.flush().await;
assert!(result.is_ok());
}
#[tokio::test]
async fn test_null_exporter_close() {
let exporter = NullExporter::new();
let result = exporter.close().await;
assert!(result.is_ok());
}
#[tokio::test]
async fn test_null_exporter_multiple_operations() {
let exporter = NullExporter::new();
let event1 = AuditEvent::new(
EventType::SessionStart,
"alice".to_string(),
"session-123".to_string(),
);
exporter.export(event1).await.unwrap();
let events = vec![AuditEvent::new(
EventType::FileUploaded,
"bob".to_string(),
"session-456".to_string(),
)];
exporter.export_batch(&events).await.unwrap();
exporter.flush().await.unwrap();
exporter.close().await.unwrap();
}
}