//! Basic Order Flow Smoke Tests //! //! Tests to validate core trading functionality including order submission, //! querying, cancellation, and position management. use super::common::*; #[tokio::test] async fn test_database_order_submission() { let result = with_timeout(async { let pool = sqlx::PgPool::connect(&database_url()) .await .map_err(|e| Box::new(e) as Box)?; // Create a test order let order_id = uuid::Uuid::new_v4(); let user_id = "smoke_test_user"; let symbol = "BTC-USD"; let order_type = "market"; let side = "buy"; let quantity = 1.0; let price = None::; // Insert order sqlx::query( r#" INSERT INTO orders ( id, user_id, symbol, order_type, side, quantity, price, status, created_at, updated_at ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, NOW(), NOW()) "# ) .bind(&order_id) .bind(user_id) .bind(symbol) .bind(order_type) .bind(side) .bind(quantity) .bind(price) .bind("pending") .execute(&pool) .await .map_err(|e| Box::new(e) as Box)?; println!("✅ Order submitted to database"); println!(" Order ID: {}", order_id); println!(" Symbol: {}", symbol); println!(" Side: {}", side); println!(" Quantity: {}", quantity); // Cleanup sqlx::query("DELETE FROM orders WHERE id = $1") .bind(&order_id) .execute(&pool) .await .map_err(|e| Box::new(e) as Box)?; pool.close().await; Ok(()) }).await; skip_if_unavailable!("PostgreSQL", { result }); } #[tokio::test] async fn test_database_order_query() { let result = with_timeout(async { let pool = sqlx::PgPool::connect(&database_url()) .await .map_err(|e| Box::new(e) as Box)?; // Create a test order let order_id = uuid::Uuid::new_v4(); let user_id = "smoke_test_user"; let symbol = "ETH-USD"; sqlx::query( r#" INSERT INTO orders ( id, user_id, symbol, order_type, side, quantity, status, created_at, updated_at ) VALUES ($1, $2, $3, $4, $5, $6, $7, NOW(), NOW()) "# ) .bind(&order_id) .bind(user_id) .bind(symbol) .bind("limit") .bind("sell") .bind(2.0) .bind("pending") .execute(&pool) .await .map_err(|e| Box::new(e) as Box)?; // Query order let order: (uuid::Uuid, String, String) = sqlx::query_as( "SELECT id, user_id, symbol FROM orders WHERE id = $1" ) .bind(&order_id) .fetch_one(&pool) .await .map_err(|e| Box::new(e) as Box)?; assert_eq!(order.0, order_id); assert_eq!(order.1, user_id); assert_eq!(order.2, symbol); println!("✅ Order query successful"); println!(" Order ID: {}", order.0); println!(" User ID: {}", order.1); println!(" Symbol: {}", order.2); // Cleanup sqlx::query("DELETE FROM orders WHERE id = $1") .bind(&order_id) .execute(&pool) .await .map_err(|e| Box::new(e) as Box)?; pool.close().await; Ok(()) }).await; skip_if_unavailable!("PostgreSQL", { result }); } #[tokio::test] async fn test_database_order_cancellation() { let result = with_timeout(async { let pool = sqlx::PgPool::connect(&database_url()) .await .map_err(|e| Box::new(e) as Box)?; // Create a test order let order_id = uuid::Uuid::new_v4(); sqlx::query( r#" INSERT INTO orders ( id, user_id, symbol, order_type, side, quantity, status, created_at, updated_at ) VALUES ($1, $2, $3, $4, $5, $6, $7, NOW(), NOW()) "# ) .bind(&order_id) .bind("smoke_test_user") .bind("BTC-USD") .bind("limit") .bind("buy") .bind(0.5) .bind("pending") .execute(&pool) .await .map_err(|e| Box::new(e) as Box)?; // Cancel order sqlx::query( "UPDATE orders SET status = $1, updated_at = NOW() WHERE id = $2" ) .bind("cancelled") .bind(&order_id) .execute(&pool) .await .map_err(|e| Box::new(e) as Box)?; // Verify cancellation let status: (String,) = sqlx::query_as( "SELECT status FROM orders WHERE id = $1" ) .bind(&order_id) .fetch_one(&pool) .await .map_err(|e| Box::new(e) as Box)?; assert_eq!(status.0, "cancelled"); println!("✅ Order cancellation successful"); println!(" Order ID: {}", order_id); println!(" Status: {}", status.0); // Cleanup sqlx::query("DELETE FROM orders WHERE id = $1") .bind(&order_id) .execute(&pool) .await .map_err(|e| Box::new(e) as Box)?; pool.close().await; Ok(()) }).await; skip_if_unavailable!("PostgreSQL", { result }); } #[tokio::test] async fn test_database_position_management() { let result = with_timeout(async { let pool = sqlx::PgPool::connect(&database_url()) .await .map_err(|e| Box::new(e) as Box)?; let position_id = uuid::Uuid::new_v4(); let user_id = "smoke_test_user"; let symbol = "BTC-USD"; let quantity = 1.5; let entry_price = 50000.0; // Create position sqlx::query( r#" INSERT INTO positions ( id, user_id, symbol, quantity, entry_price, current_price, unrealized_pnl, created_at, updated_at ) VALUES ($1, $2, $3, $4, $5, $6, $7, NOW(), NOW()) "# ) .bind(&position_id) .bind(user_id) .bind(symbol) .bind(quantity) .bind(entry_price) .bind(entry_price) // current_price = entry_price initially .bind(0.0) // unrealized_pnl = 0 initially .execute(&pool) .await .map_err(|e| Box::new(e) as Box)?; // Query position let position: (uuid::Uuid, String, f64, f64) = sqlx::query_as( "SELECT id, symbol, quantity, entry_price FROM positions WHERE id = $1" ) .bind(&position_id) .fetch_one(&pool) .await .map_err(|e| Box::new(e) as Box)?; assert_eq!(position.0, position_id); assert_eq!(position.1, symbol); assert_eq!(position.2, quantity); assert_eq!(position.3, entry_price); println!("✅ Position management successful"); println!(" Position ID: {}", position.0); println!(" Symbol: {}", position.1); println!(" Quantity: {}", position.2); println!(" Entry Price: ${}", position.3); // Cleanup sqlx::query("DELETE FROM positions WHERE id = $1") .bind(&position_id) .execute(&pool) .await .map_err(|e| Box::new(e) as Box)?; pool.close().await; Ok(()) }).await; skip_if_unavailable!("PostgreSQL", { result }); } #[tokio::test] async fn test_database_order_history() { let result = with_timeout(async { let pool = sqlx::PgPool::connect(&database_url()) .await .map_err(|e| Box::new(e) as Box)?; let user_id = "smoke_test_user"; // Create multiple test orders let order_ids: Vec = (0..3) .map(|_| uuid::Uuid::new_v4()) .collect(); for order_id in &order_ids { sqlx::query( r#" INSERT INTO orders ( id, user_id, symbol, order_type, side, quantity, status, created_at, updated_at ) VALUES ($1, $2, $3, $4, $5, $6, $7, NOW(), NOW()) "# ) .bind(order_id) .bind(user_id) .bind("BTC-USD") .bind("market") .bind("buy") .bind(0.1) .bind("filled") .execute(&pool) .await .map_err(|e| Box::new(e) as Box)?; } // Query order history let orders: Vec<(uuid::Uuid, String)> = sqlx::query_as( "SELECT id, status FROM orders WHERE user_id = $1 ORDER BY created_at DESC LIMIT 10" ) .bind(user_id) .fetch_all(&pool) .await .map_err(|e| Box::new(e) as Box)?; assert!(orders.len() >= 3, "Should find at least 3 orders"); println!("✅ Order history query successful"); println!(" Found {} orders for user {}", orders.len(), user_id); // Cleanup for order_id in &order_ids { sqlx::query("DELETE FROM orders WHERE id = $1") .bind(order_id) .execute(&pool) .await .map_err(|e| Box::new(e) as Box)?; } pool.close().await; Ok(()) }).await; skip_if_unavailable!("PostgreSQL", { result }); } #[tokio::test] async fn test_complete_order_lifecycle() { println!("🔄 Running complete order lifecycle..."); let mut steps_passed = 0; let total_steps = 4; if let Ok(pool) = sqlx::PgPool::connect(&database_url()).await { let order_id = uuid::Uuid::new_v4(); // Step 1: Submit order if sqlx::query( r#" INSERT INTO orders ( id, user_id, symbol, order_type, side, quantity, status, created_at, updated_at ) VALUES ($1, $2, $3, $4, $5, $6, $7, NOW(), NOW()) "# ) .bind(&order_id) .bind("smoke_test_user") .bind("BTC-USD") .bind("market") .bind("buy") .bind(1.0) .bind("pending") .execute(&pool) .await .is_ok() { println!(" ✓ Order submission"); steps_passed += 1; } // Step 2: Query order if sqlx::query_as::<_, (String,)>( "SELECT status FROM orders WHERE id = $1" ) .bind(&order_id) .fetch_one(&pool) .await .is_ok() { println!(" ✓ Order query"); steps_passed += 1; } // Step 3: Update order if sqlx::query( "UPDATE orders SET status = $1, updated_at = NOW() WHERE id = $2" ) .bind("filled") .bind(&order_id) .execute(&pool) .await .is_ok() { println!(" ✓ Order update"); steps_passed += 1; } // Step 4: Cancel/cleanup if sqlx::query("DELETE FROM orders WHERE id = $1") .bind(&order_id) .execute(&pool) .await .is_ok() { println!(" ✓ Order cleanup"); steps_passed += 1; } pool.close().await; } else { println!(" ⚠ Database unavailable - skipping order lifecycle test"); return; } println!("\n📊 Order Lifecycle Summary:"); println!(" Steps passed: {}/{}", steps_passed, total_steps); assert_eq!(steps_passed, total_steps, "Complete order lifecycle should pass all steps"); println!("✅ Order lifecycle check complete"); }