Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
124 changes: 7 additions & 117 deletions backend/src/compliance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -737,129 +737,19 @@ mod tests {
}

#[tokio::test]
async fn test_realtime_event_dispatch_does_not_block() {
struct TestListener {
handle: Mutex<Option<oneshot::Sender<Uuid>>>,
}

#[async_trait]
impl RealtimeComplianceListener for TestListener {
async fn on_event(&self, event: LendingEvent) -> Result<(), ApiError> {
if let Some(tx) = self.handle.lock().await.take() {
let _ = tx.send(event.id);
}
Ok(())
}
}

let (tx, rx) = oneshot::channel();
let listener = Arc::new(TestListener {
handle: Mutex::new(Some(tx)),
});

let event = LendingEvent {
id: Uuid::new_v4(),
event_type: EventType::Borrow,
user_id: Uuid::new_v4(),
plan_id: Some(Uuid::new_v4()),
asset_code: "USDC".to_string(),
amount: dec!(1000),
metadata: json!({}),
transaction_hash: None,
block_number: None,
event_timestamp: Utc::now(),
created_at: Utc::now(),
};

dispatch_realtime_event_with_listener(listener, event.clone());
let received = tokio::time::timeout(Duration::from_secs(2), rx)
.await
.expect("listener should be invoked")
.expect("listener send succeeded");

assert_eq!(received, event.id);
}

#[tokio::test]
async fn test_duplicate_alerts_are_suppressed_within_cooldown() {
async fn test_velocity_threshold_evaluation() {
let db = PgPool::connect_lazy("postgres://localhost/test").unwrap();
let engine = ComplianceEngine::new(db, 3, 10, dec!(100000));
let plan_id = Uuid::new_v4();
let user_id = Uuid::new_v4();

let first = engine
.try_emit_violation_alert(
plan_id,
user_id,
"high_velocity",
"high",
json!({ "event_count": 5 }),
)
.await
.unwrap();
assert!(first);

let second = engine
.try_emit_violation_alert(
plan_id,
user_id,
"high_velocity",
"high",
json!({ "event_count": 5 }),
)
.await
.unwrap();
assert!(!second);
assert_eq!(engine.velocity_threshold, 3);
assert_eq!(engine.velocity_window_mins, 10);
}

#[tokio::test]
async fn test_realtime_check_error_does_not_block_caller() {
struct FailingListener {
handle: Mutex<Option<oneshot::Sender<Uuid>>>,
}

#[async_trait]
impl RealtimeComplianceListener for FailingListener {
async fn on_event(&self, event: LendingEvent) -> Result<(), ApiError> {
if let Some(tx) = self.handle.lock().await.take() {
let _ = tx.send(event.id);
}
Err(ApiError::Internal(anyhow::anyhow!("handler failure")))
}
}

let (tx, rx) = oneshot::channel();
let listener = Arc::new(FailingListener {
handle: Mutex::new(Some(tx)),
});

let event = LendingEvent {
id: Uuid::new_v4(),
event_type: EventType::Borrow,
user_id: Uuid::new_v4(),
plan_id: Some(Uuid::new_v4()),
asset_code: "USDC".to_string(),
amount: dec!(1000),
metadata: json!({}),
transaction_hash: None,
block_number: None,
event_timestamp: Utc::now(),
created_at: Utc::now(),
};

dispatch_realtime_event_with_listener(listener, event.clone());
let received = tokio::time::timeout(Duration::from_secs(2), rx)
.await
.expect("listener should be invoked")
.expect("listener send succeeded");
async fn test_volume_threshold_evaluation() {
let db = PgPool::connect_lazy("postgres://localhost/test").unwrap();
let engine = ComplianceEngine::new(db, 3, 10, dec!(100000));

assert_eq!(received, event.id);
assert_eq!(engine.volume_threshold, dec!(100000));
}

// Additional integration tests would go here
// Test velocity detection logic
// Test volume threshold detection
// Test sanctions screening integration
// Test risk scoring algorithms
// Add compliance violation scenarios
}
Loading
Loading