//! Agent Commands Integration Tests //! //! Test suite for `tli agent` commands including portfolio allocation. //! Uses TDD approach with tests written before implementation. use tli::commands::agent::{AllocatePortfolioArgs, handle_allocate_portfolio}; #[tokio::test] async fn test_allocate_portfolio_valid_args() { let args = AllocatePortfolioArgs { selection_id: "test-selection-123".to_string(), total_capital: 100000.0, strategy: "ml-optimized".to_string(), max_position_size: 0.20, min_position_size: 0.05, }; // This will fail until Trading Agent Service is running // For now, test that the function signature is correct let result = handle_allocate_portfolio( args, "http://localhost:50051", "mock-jwt-token", ).await; // Expected to fail with connection error when service is not running // But should not panic or have type errors assert!(result.is_err() || result.is_ok()); } #[tokio::test] async fn test_allocate_portfolio_negative_capital() { let args = AllocatePortfolioArgs { selection_id: "test-selection-123".to_string(), total_capital: -1000.0, strategy: "ml-optimized".to_string(), max_position_size: 0.20, min_position_size: 0.05, }; let result = handle_allocate_portfolio( args, "http://localhost:50051", "mock-jwt-token", ).await; assert!(result.is_err()); let error = result.unwrap_err(); eprintln!("Error: {}", error); assert!(error.to_string().contains("positive") || error.to_string().contains("Invalid portfolio allocation constraints")); } #[tokio::test] async fn test_allocate_portfolio_zero_capital() { let args = AllocatePortfolioArgs { selection_id: "test-selection-123".to_string(), total_capital: 0.0, strategy: "ml-optimized".to_string(), max_position_size: 0.20, min_position_size: 0.05, }; let result = handle_allocate_portfolio( args, "http://localhost:50051", "mock-jwt-token", ).await; assert!(result.is_err()); } #[tokio::test] async fn test_allocate_portfolio_invalid_strategy() { let args = AllocatePortfolioArgs { selection_id: "test-selection-123".to_string(), total_capital: 100000.0, strategy: "invalid-strategy-xyz".to_string(), max_position_size: 0.20, min_position_size: 0.05, }; let result = handle_allocate_portfolio( args, "http://localhost:50051", "mock-jwt-token", ).await; assert!(result.is_err()); let error = result.unwrap_err(); assert!(error.to_string().contains("Unknown allocation strategy") || error.to_string().contains("allocation strategy")); } #[tokio::test] async fn test_allocate_portfolio_min_size_too_small() { let args = AllocatePortfolioArgs { selection_id: "test-selection-123".to_string(), total_capital: 100000.0, strategy: "ml-optimized".to_string(), max_position_size: 0.20, min_position_size: 0.0, }; let result = handle_allocate_portfolio( args, "http://localhost:50051", "mock-jwt-token", ).await; assert!(result.is_err(), "Expected error for min_position_size = 0.0"); } #[tokio::test] async fn test_allocate_portfolio_max_size_too_large() { let args = AllocatePortfolioArgs { selection_id: "test-selection-123".to_string(), total_capital: 100000.0, strategy: "ml-optimized".to_string(), max_position_size: 1.5, min_position_size: 0.05, }; let result = handle_allocate_portfolio( args, "http://localhost:50051", "mock-jwt-token", ).await; assert!(result.is_err(), "Expected error for max_position_size = 1.5"); } #[tokio::test] async fn test_allocate_portfolio_min_greater_than_max() { let args = AllocatePortfolioArgs { selection_id: "test-selection-123".to_string(), total_capital: 100000.0, strategy: "ml-optimized".to_string(), max_position_size: 0.10, min_position_size: 0.20, }; let result = handle_allocate_portfolio( args, "http://localhost:50051", "mock-jwt-token", ).await; assert!(result.is_err(), "Expected error for min > max"); } #[tokio::test] async fn test_allocate_portfolio_equal_weight_strategy() { let args = AllocatePortfolioArgs { selection_id: "test-selection-123".to_string(), total_capital: 100000.0, strategy: "equal-weight".to_string(), max_position_size: 0.20, min_position_size: 0.05, }; let result = handle_allocate_portfolio( args, "http://localhost:50051", "mock-jwt-token", ).await; // Should parse strategy correctly (may fail with connection error) assert!(result.is_err() || result.is_ok()); } #[tokio::test] async fn test_allocate_portfolio_risk_parity_strategy() { let args = AllocatePortfolioArgs { selection_id: "test-selection-123".to_string(), total_capital: 100000.0, strategy: "risk-parity".to_string(), max_position_size: 0.20, min_position_size: 0.05, }; let result = handle_allocate_portfolio( args, "http://localhost:50051", "mock-jwt-token", ).await; // Should parse strategy correctly (may fail with connection error) assert!(result.is_err() || result.is_ok()); } #[tokio::test] async fn test_allocate_portfolio_mean_variance_strategy() { let args = AllocatePortfolioArgs { selection_id: "test-selection-123".to_string(), total_capital: 100000.0, strategy: "mean-variance".to_string(), max_position_size: 0.20, min_position_size: 0.05, }; let result = handle_allocate_portfolio( args, "http://localhost:50051", "mock-jwt-token", ).await; // Should parse strategy correctly (may fail with connection error) assert!(result.is_err() || result.is_ok()); } #[tokio::test] async fn test_allocate_portfolio_kelly_strategy() { let args = AllocatePortfolioArgs { selection_id: "test-selection-123".to_string(), total_capital: 100000.0, strategy: "kelly".to_string(), max_position_size: 0.20, min_position_size: 0.05, }; let result = handle_allocate_portfolio( args, "http://localhost:50051", "mock-jwt-token", ).await; // Should parse strategy correctly (may fail with connection error) assert!(result.is_err() || result.is_ok()); } #[tokio::test] async fn test_allocate_portfolio_case_insensitive_strategy() { let args = AllocatePortfolioArgs { selection_id: "test-selection-123".to_string(), total_capital: 100000.0, strategy: "ML-OPTIMIZED".to_string(), max_position_size: 0.20, min_position_size: 0.05, }; let result = handle_allocate_portfolio( args, "http://localhost:50051", "mock-jwt-token", ).await; // Should parse strategy correctly (may fail with connection error) assert!(result.is_err() || result.is_ok()); } #[test] fn test_allocate_portfolio_args_struct() { // Test that AllocatePortfolioArgs can be constructed let args = AllocatePortfolioArgs { selection_id: "test-123".to_string(), total_capital: 100000.0, strategy: "ml-optimized".to_string(), max_position_size: 0.20, min_position_size: 0.05, }; assert_eq!(args.selection_id, "test-123"); assert_eq!(args.total_capital, 100000.0); assert_eq!(args.strategy, "ml-optimized"); assert_eq!(args.max_position_size, 0.20); assert_eq!(args.min_position_size, 0.05); } #[test] fn test_allocate_portfolio_args_clone() { // Test that AllocatePortfolioArgs implements Clone let args = AllocatePortfolioArgs { selection_id: "test-123".to_string(), total_capital: 100000.0, strategy: "ml-optimized".to_string(), max_position_size: 0.20, min_position_size: 0.05, }; let cloned = args.clone(); assert_eq!(args.selection_id, cloned.selection_id); assert_eq!(args.total_capital, cloned.total_capital); } #[test] fn test_allocate_portfolio_args_debug() { // Test that AllocatePortfolioArgs implements Debug let args = AllocatePortfolioArgs { selection_id: "test-123".to_string(), total_capital: 100000.0, strategy: "ml-optimized".to_string(), max_position_size: 0.20, min_position_size: 0.05, }; let debug_str = format!("{:?}", args); assert!(debug_str.contains("test-123")); assert!(debug_str.contains("100000")); }