---
to: generated/tests/{{name}}_integration_test.rs
vars:
  name: "user"
  description: "Integration tests for user service"
sparql:
  find_test_scenarios: "SELECT ?scenario ?name WHERE { ?scenario a ex:TestScenario ; ex:name ?name }"
  find_test_data: "SELECT ?data ?type WHERE { ?data a ex:TestData ; ex:type ?type }"
freeze_policy: "checksum"
freeze_slots_dir: "generated/.ggen/freeze"
---

//! {{description}}
//! 
//! Comprehensive integration tests that run from the lifecycle system including:
//! - End-to-end API testing
//! - Database integration testing
//! - Performance benchmarking
//! - Security testing
//! - Load testing
//! - Chaos engineering tests
//!
//! Generated by ggen on {{ "now" | date(format="%Y-%m-%d %H:%M:%S") }}

use anyhow::Result;
use axum::{
    body::Body,
    http::{Request, StatusCode},
    Router,
};
use serde_json::json;
use sqlx::{PgPool, Row};
use std::collections::HashMap;
use tokio::time::{timeout, Duration};
use tower::ServiceExt;
use uuid::Uuid;

/// Test configuration
#[derive(Debug, Clone)]
pub struct TestConfig {
    pub database_url: String,
    pub api_base_url: String,
    pub timeout_seconds: u64,
    pub max_retries: u32,
    pub enable_performance_tests: bool,
    pub enable_security_tests: bool,
    pub enable_chaos_tests: bool,
}

impl Default for TestConfig {
    fn default() -> Self {
        Self {
            database_url: "postgresql://localhost/comprehensive_showcase_test".to_string(),
            api_base_url: "http://localhost:3000".to_string(),
            timeout_seconds: 30,
            max_retries: 3,
            enable_performance_tests: true,
            enable_security_tests: true,
            enable_chaos_tests: false,
        }
    }
}

/// Test data factory
pub struct TestDataFactory {
    config: TestConfig,
    db_pool: PgPool,
}

impl TestDataFactory {
    pub async fn new(config: TestConfig) -> Result<Self> {
        let db_pool = PgPool::connect(&config.database_url)
            .await
            .context("Failed to connect to test database")?;

        Ok(Self { config, db_pool })
    }

    pub async fn create_test_{{name}}(&self) -> Result<Uuid> {
        let id = Uuid::new_v4();
        let name = format!("Test {{name}} {}", id);
        let email = format!("test-{}@example.com", id);

        sqlx::query!(
            "INSERT INTO users (id, name, email) VALUES ($1, $2, $3)",
            id,
            name,
            email
        )
        .execute(&self.db_pool)
        .await
        .context("Failed to create test {{name}}")?;

        Ok(id)
    }

    pub async fn cleanup_test_data(&self) -> Result<()> {
        sqlx::query!("DELETE FROM users WHERE email LIKE 'test-%@example.com'")
            .execute(&self.db_pool)
            .await
            .context("Failed to cleanup test data")?;

        Ok(())
    }
}

/// Performance test metrics
#[derive(Debug, Clone)]
pub struct PerformanceMetrics {
    pub response_time_ms: u64,
    pub throughput_rps: f64,
    pub error_rate: f64,
    pub memory_usage_mb: f64,
    pub cpu_usage_percent: f64,
}

/// Security test results
#[derive(Debug, Clone)]
pub struct SecurityTestResults {
    pub vulnerabilities_found: u32,
    pub security_score: f64,
    pub failed_tests: Vec<String>,
    pub recommendations: Vec<String>,
}

/// Test suite for {{name}} service
pub struct {{name | title}}TestSuite {
    config: TestConfig,
    data_factory: TestDataFactory,
    app: Router,
}

impl {{name | title}}TestSuite {
    pub async fn new(config: TestConfig) -> Result<Self> {
        let data_factory = TestDataFactory::new(config.clone()).await?;
        
        // Create the application router for testing
        let app = create_test_app().await?;

        Ok(Self {
            config,
            data_factory,
            app,
        })
    }

    /// Run all integration tests
    pub async fn run_all_tests(&self) -> Result<()> {
        println!("🧪 Running comprehensive {{name}} integration tests...");

        // Basic functionality tests
        self.test_create_{{name}}().await?;
        self.test_get_{{name}}().await?;
        self.test_update_{{name}}().await?;
        self.test_delete_{{name}}().await?;
        self.test_list_{{name}}s().await?;

        // Error handling tests
        self.test_error_handling().await?;

        // Validation tests
        self.test_validation().await?;

        // Database integration tests
        self.test_database_integration().await?;

        // Performance tests
        if self.config.enable_performance_tests {
            self.test_performance().await?;
        }

        // Security tests
        if self.config.enable_security_tests {
            self.test_security().await?;
        }

        // Chaos engineering tests
        if self.config.enable_chaos_tests {
            self.test_chaos_engineering().await?;
        }

        println!("✅ All {{name}} integration tests passed!");
        Ok(())
    }

    /// Test {{name}} creation
    async fn test_create_{{name}}(&self) -> Result<()> {
        println!("  📝 Testing {{name}} creation...");

        let request_body = json!({
            "name": "Test User",
            "email": "test@example.com"
        });

        let request = Request::builder()
            .method("POST")
            .uri("/{{name}}s")
            .header("content-type", "application/json")
            .body(Body::from(request_body.to_string()))?;

        let response = self.app.clone().oneshot(request).await?;
        assert_eq!(response.status(), StatusCode::CREATED);

        let body = hyper::body::to_bytes(response.into_body()).await?;
        let response_json: serde_json::Value = serde_json::from_slice(&body)?;
        
        assert!(response_json["success"].as_bool().unwrap());
        assert!(response_json["data"].is_object());
        assert_eq!(response_json["data"]["name"], "Test User");
        assert_eq!(response_json["data"]["email"], "test@example.com");

        println!("    ✅ {{name}} creation test passed");
        Ok(())
    }

    /// Test {{name}} retrieval
    async fn test_get_{{name}}(&self) -> Result<()> {
        println!("  📖 Testing {{name}} retrieval...");

        // First create a {{name}}
        let {{name}}_id = self.data_factory.create_test_{{name}}().await?;

        let request = Request::builder()
            .method("GET")
            .uri(&format!("/{{name}}s/{}", {{name}}_id))
            .body(Body::empty())?;

        let response = self.app.clone().oneshot(request).await?;
        assert_eq!(response.status(), StatusCode::OK);

        let body = hyper::body::to_bytes(response.into_body()).await?;
        let response_json: serde_json::Value = serde_json::from_slice(&body)?;
        
        assert!(response_json["success"].as_bool().unwrap());
        assert!(response_json["data"].is_object());
        assert_eq!(response_json["data"]["id"], {{name}}_id.to_string());

        println!("    ✅ {{name}} retrieval test passed");
        Ok(())
    }

    /// Test {{name}} update
    async fn test_update_{{name}}(&self) -> Result<()> {
        println!("  ✏️ Testing {{name}} update...");

        // First create a {{name}}
        let {{name}}_id = self.data_factory.create_test_{{name}}().await?;

        let request_body = json!({
            "name": "Updated User",
            "email": "updated@example.com"
        });

        let request = Request::builder()
            .method("PUT")
            .uri(&format!("/{{name}}s/{}", {{name}}_id))
            .header("content-type", "application/json")
            .body(Body::from(request_body.to_string()))?;

        let response = self.app.clone().oneshot(request).await?;
        assert_eq!(response.status(), StatusCode::OK);

        let body = hyper::body::to_bytes(response.into_body()).await?;
        let response_json: serde_json::Value = serde_json::from_slice(&body)?;
        
        assert!(response_json["success"].as_bool().unwrap());
        assert_eq!(response_json["data"]["name"], "Updated User");
        assert_eq!(response_json["data"]["email"], "updated@example.com");

        println!("    ✅ {{name}} update test passed");
        Ok(())
    }

    /// Test {{name}} deletion
    async fn test_delete_{{name}}(&self) -> Result<()> {
        println!("  🗑️ Testing {{name}} deletion...");

        // First create a {{name}}
        let {{name}}_id = self.data_factory.create_test_{{name}}().await?;

        let request = Request::builder()
            .method("DELETE")
            .uri(&format!("/{{name}}s/{}", {{name}}_id))
            .body(Body::empty())?;

        let response = self.app.clone().oneshot(request).await?;
        assert_eq!(response.status(), StatusCode::OK);

        // Verify {{name}} is deleted
        let request = Request::builder()
            .method("GET")
            .uri(&format!("/{{name}}s/{}", {{name}}_id))
            .body(Body::empty())?;

        let response = self.app.clone().oneshot(request).await?;
        assert_eq!(response.status(), StatusCode::NOT_FOUND);

        println!("    ✅ {{name}} deletion test passed");
        Ok(())
    }

    /// Test {{name}} listing with pagination
    async fn test_list_{{name}}s(&self) -> Result<()> {
        println!("  📋 Testing {{name}} listing...");

        // Create multiple test {{name}}s
        for i in 0..5 {
            self.data_factory.create_test_{{name}}().await?;
        }

        let request = Request::builder()
            .method("GET")
            .uri("/{{name}}s?page=1&limit=10")
            .body(Body::empty())?;

        let response = self.app.clone().oneshot(request).await?;
        assert_eq!(response.status(), StatusCode::OK);

        let body = hyper::body::to_bytes(response.into_body()).await?;
        let response_json: serde_json::Value = serde_json::from_slice(&body)?;
        
        assert!(response_json["success"].as_bool().unwrap());
        assert!(response_json["data"]["items"].is_array());
        assert!(response_json["data"]["pagination"].is_object());

        println!("    ✅ {{name}} listing test passed");
        Ok(())
    }

    /// Test error handling
    async fn test_error_handling(&self) -> Result<()> {
        println!("  ❌ Testing error handling...");

        // Test 404 for non-existent {{name}}
        let non_existent_id = Uuid::new_v4();
        let request = Request::builder()
            .method("GET")
            .uri(&format!("/{{name}}s/{}", non_existent_id))
            .body(Body::empty())?;

        let response = self.app.clone().oneshot(request).await?;
        assert_eq!(response.status(), StatusCode::NOT_FOUND);

        // Test 400 for invalid request
        let invalid_request_body = json!({
            "name": "", // Invalid empty name
            "email": "invalid-email" // Invalid email format
        });

        let request = Request::builder()
            .method("POST")
            .uri("/{{name}}s")
            .header("content-type", "application/json")
            .body(Body::from(invalid_request_body.to_string()))?;

        let response = self.app.clone().oneshot(request).await?;
        assert_eq!(response.status(), StatusCode::BAD_REQUEST);

        println!("    ✅ Error handling test passed");
        Ok(())
    }

    /// Test input validation
    async fn test_validation(&self) -> Result<()> {
        println!("  ✅ Testing input validation...");

        // Test email validation
        let invalid_email_body = json!({
            "name": "Test User",
            "email": "not-an-email"
        });

        let request = Request::builder()
            .method("POST")
            .uri("/{{name}}s")
            .header("content-type", "application/json")
            .body(Body::from(invalid_email_body.to_string()))?;

        let response = self.app.clone().oneshot(request).await?;
        assert_eq!(response.status(), StatusCode::BAD_REQUEST);

        // Test name length validation
        let long_name_body = json!({
            "name": "a".repeat(101), // Too long
            "email": "test@example.com"
        });

        let request = Request::builder()
            .method("POST")
            .uri("/{{name}}s")
            .header("content-type", "application/json")
            .body(Body::from(long_name_body.to_string()))?;

        let response = self.app.clone().oneshot(request).await?;
        assert_eq!(response.status(), StatusCode::BAD_REQUEST);

        println!("    ✅ Input validation test passed");
        Ok(())
    }

    /// Test database integration
    async fn test_database_integration(&self) -> Result<()> {
        println!("  🗄️ Testing database integration...");

        // Test database connection
        let pool = sqlx::PgPool::connect(&self.config.database_url).await?;
        let result: i64 = sqlx::query_scalar!("SELECT 1 as one")
            .fetch_one(&pool)
            .await?;
        assert_eq!(result, 1);

        // Test transaction rollback
        let mut tx = pool.begin().await?;
        let {{name}}_id = Uuid::new_v4();
        
        sqlx::query!(
            "INSERT INTO users (id, name, email) VALUES ($1, $2, $3)",
            {{name}}_id,
            "Transaction Test",
            "transaction@example.com"
        )
        .execute(&mut *tx)
        .await?;

        tx.rollback().await?;

        // Verify rollback worked
        let count: i64 = sqlx::query_scalar!(
            "SELECT COUNT(*) FROM users WHERE id = $1",
            {{name}}_id
        )
        .fetch_one(&pool)
        .await?;
        assert_eq!(count, 0);

        println!("    ✅ Database integration test passed");
        Ok(())
    }

    /// Test performance benchmarks
    async fn test_performance(&self) -> Result<()> {
        println!("  ⚡ Testing performance...");

        let start_time = std::time::Instant::now();
        let mut request_count = 0;
        let mut error_count = 0;

        // Run 100 concurrent requests
        let mut handles = Vec::new();
        for i in 0..100 {
            let app = self.app.clone();
            let handle = tokio::spawn(async move {
                let request_body = json!({
                    "name": format!("Performance Test User {}", i),
                    "email": format!("perf-test-{}@example.com", i)
                });

                let request = Request::builder()
                    .method("POST")
                    .uri("/{{name}}s")
                    .header("content-type", "application/json")
                    .body(Body::from(request_body.to_string()))
                    .unwrap();

                match app.oneshot(request).await {
                    Ok(response) => {
                        if response.status().is_success() {
                            Ok(())
                        } else {
                            Err(anyhow::anyhow!("Request failed"))
                        }
                    }
                    Err(e) => Err(anyhow::anyhow!("Request error: {}", e)),
                }
            });
            handles.push(handle);
        }

        for handle in handles {
            match handle.await? {
                Ok(_) => request_count += 1,
                Err(_) => error_count += 1,
            }
        }

        let duration = start_time.elapsed();
        let throughput = request_count as f64 / duration.as_secs_f64();
        let error_rate = error_count as f64 / (request_count + error_count) as f64;

        println!("    📊 Performance metrics:");
        println!("      - Total requests: {}", request_count);
        println!("      - Errors: {}", error_count);
        println!("      - Duration: {:?}", duration);
        println!("      - Throughput: {:.2} req/s", throughput);
        println!("      - Error rate: {:.2}%", error_rate * 100.0);

        // Assert performance thresholds
        assert!(throughput > 10.0, "Throughput too low: {:.2} req/s", throughput);
        assert!(error_rate < 0.05, "Error rate too high: {:.2}%", error_rate * 100.0);

        println!("    ✅ Performance test passed");
        Ok(())
    }

    /// Test security vulnerabilities
    async fn test_security(&self) -> Result<()> {
        println!("  🔒 Testing security...");

        let mut vulnerabilities = Vec::new();

        // Test SQL injection protection
        let sql_injection_body = json!({
            "name": "'; DROP TABLE users; --",
            "email": "test@example.com"
        });

        let request = Request::builder()
            .method("POST")
            .uri("/{{name}}s")
            .header("content-type", "application/json")
            .body(Body::from(sql_injection_body.to_string()))?;

        let response = self.app.clone().oneshot(request).await?;
        if response.status() == StatusCode::BAD_REQUEST {
            println!("    ✅ SQL injection protection working");
        } else {
            vulnerabilities.push("SQL injection vulnerability detected".to_string());
        }

        // Test XSS protection
        let xss_body = json!({
            "name": "<script>alert('xss')</script>",
            "email": "test@example.com"
        });

        let request = Request::builder()
            .method("POST")
            .uri("/{{name}}s")
            .header("content-type", "application/json")
            .body(Body::from(xss_body.to_string()))?;

        let response = self.app.clone().oneshot(request).await?;
        if response.status() == StatusCode::BAD_REQUEST {
            println!("    ✅ XSS protection working");
        } else {
            vulnerabilities.push("XSS vulnerability detected".to_string());
        }

        // Test rate limiting
        let mut rate_limit_hit = false;
        for _ in 0..1000 {
            let request = Request::builder()
                .method("GET")
                .uri("/{{name}}s")
                .body(Body::empty())?;

            let response = self.app.clone().oneshot(request).await?;
            if response.status() == StatusCode::TOO_MANY_REQUESTS {
                rate_limit_hit = true;
                break;
            }
        }

        if rate_limit_hit {
            println!("    ✅ Rate limiting working");
        } else {
            vulnerabilities.push("Rate limiting not working".to_string());
        }

        if vulnerabilities.is_empty() {
            println!("    ✅ Security test passed");
        } else {
            println!("    ❌ Security vulnerabilities found:");
            for vuln in &vulnerabilities {
                println!("      - {}", vuln);
            }
            return Err(anyhow::anyhow!("Security test failed"));
        }

        Ok(())
    }

    /// Test chaos engineering scenarios
    async fn test_chaos_engineering(&self) -> Result<()> {
        println!("  🌪️ Testing chaos engineering...");

        // Test service resilience under load
        let mut handles = Vec::new();
        for i in 0..50 {
            let app = self.app.clone();
            let handle = tokio::spawn(async move {
                let request_body = json!({
                    "name": format!("Chaos Test User {}", i),
                    "email": format!("chaos-test-{}@example.com", i)
                });

                let request = Request::builder()
                    .method("POST")
                    .uri("/{{name}}s")
                    .header("content-type", "application/json")
                    .body(Body::from(request_body.to_string()))
                    .unwrap();

                app.oneshot(request).await
            });
            handles.push(handle);
        }

        let mut success_count = 0;
        for handle in handles {
            if let Ok(Ok(response)) = handle.await {
                if response.status().is_success() {
                    success_count += 1;
                }
            }
        }

        let success_rate = success_count as f64 / 50.0;
        println!("    📊 Chaos test success rate: {:.2}%", success_rate * 100.0);

        assert!(success_rate > 0.8, "Service not resilient under load");

        println!("    ✅ Chaos engineering test passed");
        Ok(())
    }

    /// Cleanup test data
    pub async fn cleanup(&self) -> Result<()> {
        self.data_factory.cleanup_test_data().await?;
        Ok(())
    }
}

/// Create test application
async fn create_test_app() -> Result<Router> {
    // This would normally create the actual application
    // For testing, we'll create a mock router
    let app = Router::new()
        .route("/{{name}}s", axum::routing::post(|| async { "created" }))
        .route("/{{name}}s", axum::routing::get(|| async { "listed" }))
        .route("/{{name}}s/:id", axum::routing::get(|| async { "retrieved" }))
        .route("/{{name}}s/:id", axum::routing::put(|| async { "updated" }))
        .route("/{{name}}s/:id", axum::routing::delete(|| async { "deleted" }));

    Ok(app)
}

/// Main test runner
#[tokio::test]
async fn test_{{name}}_service_integration() -> Result<()> {
    // Initialize tracing for tests
    tracing_subscriber::fmt()
        .with_env_filter("debug")
        .init();

    let config = TestConfig::default();
    let test_suite = {{name | title}}TestSuite::new(config).await?;

    // Run all tests
    test_suite.run_all_tests().await?;

    // Cleanup
    test_suite.cleanup().await?;

    Ok(())
}

/// Performance benchmark tests
#[tokio::test]
async fn benchmark_{{name}}_performance() -> Result<()> {
    let config = TestConfig {
        enable_performance_tests: true,
        ..Default::default()
    };

    let test_suite = {{name | title}}TestSuite::new(config).await?;
    test_suite.test_performance().await?;
    test_suite.cleanup().await?;

    Ok(())
}

/// Security test suite
#[tokio::test]
async fn test_{{name}}_security() -> Result<()> {
    let config = TestConfig {
        enable_security_tests: true,
        ..Default::default()
    };

    let test_suite = {{name | title}}TestSuite::new(config).await?;
    test_suite.test_security().await?;
    test_suite.cleanup().await?;

    Ok(())
}

/// Chaos engineering tests
#[tokio::test]
async fn test_{{name}}_chaos() -> Result<()> {
    let config = TestConfig {
        enable_chaos_tests: true,
        ..Default::default()
    };

    let test_suite = {{name | title}}TestSuite::new(config).await?;
    test_suite.test_chaos_engineering().await?;
    test_suite.cleanup().await?;

    Ok(())
}
