#[cfg(test)]
mod tests {
use std::time::Duration;
use chrono::{Utc, FixedOffset};
use tokio::time::sleep;
use crate::real_time_monitoring::{
MonitoringServer, MonitoringClient, MonitoringManager,
MonitoringMessage, TradeExecutionUpdate, ConnectionStatus
};
use crate::trading_mode::TradingMode;
use crate::unified_data::{OrderRequest, OrderResult, OrderSide, OrderType, OrderStatus, TimeInForce};
use crate::live_trading::AlertLevel;
#[tokio::test]
async fn test_monitoring_server_creation() {
let mut server = MonitoringServer::new(8080);
assert_eq!(server.port, 8080);
assert_eq!(server.client_count(), 0);
let result = server.start().await;
assert!(result.is_ok());
let result = server.stop().await;
assert!(result.is_ok());
}
#[tokio::test]
async fn test_monitoring_client_creation() {
let client = MonitoringClient::new("ws://localhost:8080");
assert_eq!(client.server_address, "ws://localhost:8080");
assert_eq!(client.is_connected(), false);
assert_eq!(client.connection_status(), ConnectionStatus::Disconnected);
}
#[tokio::test]
async fn test_monitoring_manager_creation() {
let manager = MonitoringManager::new(TradingMode::LiveTrade);
assert_eq!(manager.mode, TradingMode::LiveTrade);
assert_eq!(manager.get_alert_history().len(), 0);
assert_eq!(manager.get_trade_execution_history().len(), 0);
}
#[tokio::test]
async fn test_send_alert() {
let mut manager = MonitoringManager::new(TradingMode::LiveTrade);
let result = manager.send_alert(
AlertLevel::Warning,
"Test alert",
Some("BTC"),
None
);
assert!(result.is_ok());
assert_eq!(manager.get_alert_history().len(), 1);
let alert = &manager.get_alert_history()[0];
assert_eq!(alert.level, "Warning");
assert_eq!(alert.message, "Test alert");
assert_eq!(alert.symbol, Some("BTC".to_string()));
assert_eq!(alert.order_id, None);
}
#[tokio::test]
async fn test_record_trade_execution() {
let mut manager = MonitoringManager::new(TradingMode::LiveTrade);
let order_request = OrderRequest {
symbol: "BTC".to_string(),
side: OrderSide::Buy,
order_type: OrderType::Market,
quantity: 1.0,
price: None,
reduce_only: false,
time_in_force: TimeInForce::GoodTilCancelled,
};
let order_result = OrderResult {
order_id: "test_order".to_string(),
status: OrderStatus::Filled,
filled_quantity: 1.0,
average_price: Some(50000.0),
fees: Some(25.0),
timestamp: Utc::now().with_timezone(&FixedOffset::east(0)),
error: None,
};
let result = manager.record_trade_execution(&order_request, &order_result, 100);
assert!(result.is_ok());
assert_eq!(manager.get_trade_execution_history().len(), 1);
let execution = &manager.get_trade_execution_history()[0];
assert_eq!(execution.order_id, "test_order");
assert_eq!(execution.symbol, "BTC");
assert_eq!(execution.status, OrderStatus::Filled);
assert_eq!(execution.filled_quantity, 1.0);
assert_eq!(execution.average_price, Some(50000.0));
assert_eq!(execution.execution_latency_ms, 100);
assert_eq!(execution.error, None);
}
#[tokio::test]
async fn test_update_performance_metrics() {
let mut manager = MonitoringManager::new(TradingMode::LiveTrade);
let result = manager.update_performance_metrics(
10000.0, 100.0, 500.0, 0.6, 1.5, 5.0, 2 );
assert!(result.is_ok());
assert_eq!(manager.get_performance_metrics_history().len(), 1);
let metrics = &manager.get_performance_metrics_history()[0];
assert_eq!(metrics.current_balance, 10000.0);
assert_eq!(metrics.daily_pnl, 100.0);
assert_eq!(metrics.daily_pnl_pct, 1.0); assert_eq!(metrics.total_pnl, 500.0);
assert_eq!(metrics.total_return_pct, 5.0); assert_eq!(metrics.win_rate, 0.6);
assert_eq!(metrics.sharpe_ratio, 1.5);
assert_eq!(metrics.max_drawdown_pct, 5.0);
assert_eq!(metrics.positions_count, 2);
}
#[tokio::test]
async fn test_update_connection_metrics() {
let mut manager = MonitoringManager::new(TradingMode::LiveTrade);
let result = manager.update_connection_metrics(
99.5, 2, 150.0, 50.0, 25.0 );
assert!(result.is_ok());
let metrics = manager.get_connection_metrics();
assert_eq!(metrics.uptime_pct, 99.5);
assert_eq!(metrics.disconnection_count, 2);
assert_eq!(metrics.avg_reconnection_time_ms, 150.0);
assert_eq!(metrics.api_latency_ms, 50.0);
assert_eq!(metrics.ws_latency_ms, 25.0);
}
#[tokio::test]
async fn test_message_handlers() {
let mut manager = MonitoringManager::new(TradingMode::LiveTrade);
let alert_received = std::sync::Arc::new(std::sync::atomic::AtomicBool::new(false));
let alert_received_clone = alert_received.clone();
manager.add_alert_handler(move |alert| {
if alert.message == "Test alert" {
alert_received_clone.store(true, std::sync::atomic::Ordering::SeqCst);
}
});
manager.send_alert(AlertLevel::Info, "Test alert", None, None).unwrap();
assert!(alert_received.load(std::sync::atomic::Ordering::SeqCst));
let execution_received = std::sync::Arc::new(std::sync::atomic::AtomicBool::new(false));
let execution_received_clone = execution_received.clone();
manager.add_trade_execution_handler(move |execution| {
if execution.order_id == "test_order" {
execution_received_clone.store(true, std::sync::atomic::Ordering::SeqCst);
}
});
let order_request = OrderRequest {
symbol: "BTC".to_string(),
side: OrderSide::Buy,
order_type: OrderType::Market,
quantity: 1.0,
price: None,
reduce_only: false,
time_in_force: TimeInForce::GoodTilCancelled,
};
let order_result = OrderResult {
order_id: "test_order".to_string(),
status: OrderStatus::Filled,
filled_quantity: 1.0,
average_price: Some(50000.0),
fees: Some(25.0),
timestamp: Utc::now().with_timezone(&FixedOffset::east(0)),
error: None,
};
manager.record_trade_execution(&order_request, &order_result, 100).unwrap();
assert!(execution_received.load(std::sync::atomic::Ordering::SeqCst));
}
#[tokio::test]
async fn test_dashboard_update_interval() {
let mut manager = MonitoringManager::new(TradingMode::LiveTrade);
manager.set_dashboard_update_interval(1);
assert!(manager.should_update_dashboard());
let dashboard_data = crate::mode_reporting::MonitoringDashboardData {
timestamp: Utc::now().with_timezone(&FixedOffset::east(0)),
account_summary: crate::mode_reporting::AccountSummary {
total_equity: 10000.0,
available_balance: 9000.0,
margin_used: 1000.0,
margin_usage_pct: 10.0,
current_leverage: 1.0,
unrealized_pnl: 100.0,
realized_pnl: 200.0,
funding_pnl: 50.0,
},
position_summary: crate::mode_reporting::PositionSummary {
open_positions: 2,
long_positions: 1,
short_positions: 1,
total_position_value: 10000.0,
largest_position: crate::mode_reporting::PositionSnapshot {
symbol: "BTC".to_string(),
size: 1.0,
entry_price: 50000.0,
current_price: 51000.0,
unrealized_pnl: 1000.0,
unrealized_pnl_pct: 2.0,
funding_pnl: 50.0,
liquidation_price: None,
side: OrderSide::Buy,
position_age_hours: 24.0,
},
most_profitable: crate::mode_reporting::PositionSnapshot {
symbol: "BTC".to_string(),
size: 1.0,
entry_price: 50000.0,
current_price: 51000.0,
unrealized_pnl: 1000.0,
unrealized_pnl_pct: 2.0,
funding_pnl: 50.0,
liquidation_price: None,
side: OrderSide::Buy,
position_age_hours: 24.0,
},
least_profitable: crate::mode_reporting::PositionSnapshot {
symbol: "ETH".to_string(),
size: -2.0,
entry_price: 3000.0,
current_price: 3050.0,
unrealized_pnl: -100.0,
unrealized_pnl_pct: -1.67,
funding_pnl: -10.0,
liquidation_price: None,
side: OrderSide::Sell,
position_age_hours: 12.0,
},
},
order_summary: crate::mode_reporting::OrderSummary {
active_orders: 1,
filled_today: 5,
cancelled_today: 2,
rejected_today: 0,
success_rate: 0.8,
avg_fill_time_ms: 120.0,
volume_today: 50000.0,
fees_today: 25.0,
},
risk_summary: crate::mode_reporting::RiskSummary {
current_drawdown_pct: 2.0,
max_drawdown_pct: 5.0,
value_at_risk: 500.0,
daily_volatility: 1.5,
risk_allocation: std::collections::HashMap::new(),
risk_warnings: Vec::new(),
circuit_breaker_status: "Normal".to_string(),
},
system_status: crate::mode_reporting::SystemStatus {
connection_status: "Connected".to_string(),
api_latency_ms: 50.0,
ws_latency_ms: 25.0,
uptime_hours: 24.0,
memory_usage_mb: 100.0,
cpu_usage_pct: 5.0,
last_error: None,
last_error_time: None,
},
recent_alerts: Vec::new(),
performance: crate::mode_reporting::PerformanceSnapshot {
daily_pnl: 100.0,
daily_pnl_pct: 1.0,
weekly_pnl: 500.0,
weekly_pnl_pct: 5.0,
monthly_pnl: 2000.0,
monthly_pnl_pct: 20.0,
sharpe_ratio: 1.5,
sortino_ratio: 2.0,
win_rate: 0.6,
avg_win: 200.0,
avg_loss: -100.0,
profit_factor: 2.0,
},
};
manager.update_dashboard(dashboard_data).unwrap();
assert!(!manager.should_update_dashboard());
sleep(Duration::from_secs(2)).await;
assert!(manager.should_update_dashboard());
}
}