use crate::http_acceptance::helpers::http_test_client::{HttpTestClient, HttpValidators};
use anyhow::Result;
use serde_json::json;
use std::time::Duration;
#[tokio::test]
#[ignore = "HTTP acceptance test - requires server"]
async fn test_dashboard_endpoints() -> Result<()> {
let client = HttpTestClient::new("http://localhost:3000")?;
let result = client.get("/").await?;
HttpValidators::assert_status_code(&result, 200)?;
HttpValidators::assert_performance(&result, Duration::from_secs(2))?;
HttpValidators::assert_content_type(&result, "text/html")?;
assert!(
result.response.body.contains("dashboard")
|| result.response.body.contains("pmat")
|| result.response.body.contains("analysis")
);
let vendor_paths = [
"/vendor/bootstrap.css",
"/vendor/bootstrap.js",
"/vendor/chart.js",
];
for path in &vendor_paths {
let result = client.get(path).await;
if let Ok(result) = result {
assert!(result.status_code == 200 || result.status_code == 404);
HttpValidators::assert_performance(&result, Duration::from_secs(1))?;
}
}
let demo_paths = ["/demo.css", "/demo.js"];
for path in &demo_paths {
let result = client.get(path).await;
if let Ok(result) = result {
assert!(result.status_code == 200 || result.status_code == 404);
HttpValidators::assert_performance(&result, Duration::from_secs(1))?;
}
}
Ok(())
}
#[tokio::test]
#[ignore = "HTTP acceptance test - requires server"]
async fn test_core_api_v1_endpoints() -> Result<()> {
let client = HttpTestClient::new("http://localhost:3000")?;
let result = client.get("/api/summary").await?;
HttpValidators::assert_success(&result)?;
HttpValidators::assert_performance(&result, Duration::from_secs(5))?;
HttpValidators::assert_content_type(&result, "application/json")?;
if let Some(ref json) = result.response.json {
assert!(
json.get("status").is_some()
|| json.get("summary").is_some()
|| json.get("metrics").is_some()
);
}
let result = client.get("/api/metrics").await?;
HttpValidators::assert_success(&result)?;
HttpValidators::assert_performance(&result, Duration::from_secs(5))?;
HttpValidators::assert_content_type(&result, "application/json")?;
let result = client.get("/api/hotspots").await?;
HttpValidators::assert_success(&result)?;
HttpValidators::assert_performance(&result, Duration::from_secs(5))?;
let result = client.get("/api/dag").await?;
HttpValidators::assert_success(&result)?;
HttpValidators::assert_performance(&result, Duration::from_secs(5))?;
let content_type_valid = result
.response
.headers
.get("content-type")
.map(|ct| ct.contains("application/json") || ct.contains("text/plain"))
.unwrap_or(false);
assert!(
content_type_valid,
"DAG endpoint should return JSON or text/plain"
);
let result = client.get("/api/system-diagram").await?;
HttpValidators::assert_success(&result)?;
HttpValidators::assert_performance(&result, Duration::from_secs(5))?;
let result = client.get("/api/analysis").await?;
HttpValidators::assert_success(&result)?;
HttpValidators::assert_performance(&result, Duration::from_secs(10))?;
HttpValidators::assert_content_type(&result, "application/json")?;
let result = client.get("/api/recommendations").await?;
HttpValidators::assert_success(&result)?;
HttpValidators::assert_performance(&result, Duration::from_secs(8))?;
let result = client.get("/api/polyglot").await?;
HttpValidators::assert_success(&result)?;
HttpValidators::assert_performance(&result, Duration::from_secs(8))?;
let result = client.get("/api/showcase").await?;
HttpValidators::assert_success(&result)?;
HttpValidators::assert_performance(&result, Duration::from_secs(5))?;
Ok(())
}
#[tokio::test]
#[ignore = "HTTP acceptance test - requires server"]
async fn test_enhanced_api_v1_endpoints() -> Result<()> {
let client = HttpTestClient::new("http://localhost:3000")?;
let result = client.get("/api/v1/analysis/architecture").await?;
HttpValidators::assert_success(&result)?;
HttpValidators::assert_performance(&result, Duration::from_secs(10))?;
HttpValidators::assert_content_type(&result, "application/json")?;
if let Some(ref json) = result.response.json {
assert!(
json.get("architecture").is_some()
|| json.get("components").is_some()
|| json.get("structure").is_some()
);
}
let result = client.get("/api/v1/analysis/defects").await?;
HttpValidators::assert_success(&result)?;
HttpValidators::assert_performance(&result, Duration::from_secs(8))?;
HttpValidators::assert_content_type(&result, "application/json")?;
let result = client.get("/api/v1/analysis/statistics").await?;
HttpValidators::assert_success(&result)?;
HttpValidators::assert_performance(&result, Duration::from_secs(7))?;
HttpValidators::assert_content_type(&result, "application/json")?;
let result = client.get("/api/v1/analysis/diagram").await?;
HttpValidators::assert_success(&result)?;
HttpValidators::assert_performance(&result, Duration::from_secs(6))?;
let content_type_valid = result
.response
.headers
.get("content-type")
.map(|ct| {
ct.contains("application/json")
|| ct.contains("image/svg+xml")
|| ct.contains("image/png")
})
.unwrap_or(false);
assert!(
content_type_valid,
"Diagram endpoint should return JSON, SVG, or PNG"
);
let result = client.get("/api/v1/analysis/stream").await?;
assert!(
result.status_code == 200 || result.status_code == 202 || result.status_code == 404,
"Stream endpoint should return 200, 202, or 404"
);
HttpValidators::assert_performance(&result, Duration::from_secs(10))?;
Ok(())
}
#[tokio::test]
#[ignore = "HTTP acceptance test - requires server"]
async fn test_post_endpoints() -> Result<()> {
let client = HttpTestClient::new("http://localhost:3000")?;
let project_path = client.create_sample_project()?;
let trigger_data = json!({
"path": project_path.to_string_lossy(),
"analysis_types": ["complexity", "dead_code"],
"format": "json"
});
let result = client
.post("/api/v1/analysis/trigger", Some(trigger_data))
.await?;
assert!(
result.status_code == 200
|| result.status_code == 201
|| result.status_code == 202
|| result.status_code == 404
|| result.status_code == 405
);
HttpValidators::assert_performance(&result, Duration::from_secs(15))?;
let project_data = json!({
"name": "test-project",
"path": project_path.to_string_lossy(),
"language": "rust"
});
let result = client.post("/api/v1/projects", Some(project_data)).await?;
assert!(
result.status_code == 200
|| result.status_code == 201
|| result.status_code == 404
|| result.status_code == 405
);
HttpValidators::assert_performance(&result, Duration::from_secs(10))?;
let template_data = json!({
"template_name": "rust_basic",
"output_path": project_path.join("generated").to_string_lossy(),
"variables": {
"project_name": "test_project"
}
});
let result = client
.post("/api/v1/templates/generate", Some(template_data))
.await?;
assert!(
result.status_code == 200
|| result.status_code == 201
|| result.status_code == 404
|| result.status_code == 405
);
HttpValidators::assert_performance(&result, Duration::from_secs(12))?;
let quality_data = json!({
"file_path": project_path.join("src/main.rs").to_string_lossy(),
"profile": "standard"
});
let result = client
.post("/api/v1/quality-gate/check", Some(quality_data))
.await?;
assert!(result.status_code == 200 || result.status_code == 404 || result.status_code == 405);
HttpValidators::assert_performance(&result, Duration::from_secs(10))?;
Ok(())
}
#[tokio::test]
#[ignore = "HTTP acceptance test - requires server"]
async fn test_http_methods_compliance() -> Result<()> {
let client = HttpTestClient::new("http://localhost:3000")?;
let result = client.head("/api/summary").await?;
HttpValidators::assert_performance(&result, Duration::from_secs(2))?;
assert!(result.response.body.is_empty() || result.status_code == 405);
let result = client.options("/api/summary").await?;
HttpValidators::assert_performance(&result, Duration::from_secs(2))?;
if result.status_code == 200 {
let has_cors_headers = result
.response
.headers
.contains_key("access-control-allow-methods")
|| result.response.headers.contains_key("allow");
assert!(
has_cors_headers,
"OPTIONS response should include allowed methods"
);
}
let unsupported_methods = ["PATCH", "TRACE", "CONNECT"];
for method_name in &unsupported_methods {
if method_name == &"PATCH" {
let result = client
.request(reqwest::Method::PATCH, "/api/summary", None, None)
.await?;
assert!(result.status_code == 405 || result.status_code == 404);
HttpValidators::assert_performance(&result, Duration::from_secs(2))?;
}
}
Ok(())
}
#[tokio::test]
#[ignore = "HTTP acceptance test - requires server"]
async fn test_content_negotiation() -> Result<()> {
let base_client = HttpTestClient::new("http://localhost:3000")?;
let json_client = base_client.with_accept("application/json");
let result = json_client.get("/api/summary").await?;
if result.success {
HttpValidators::assert_content_type(&result, "application/json")?;
}
let html_client = HttpTestClient::new("http://localhost:3000")?.with_accept("text/html");
let result = html_client.get("/").await?;
if result.success {
HttpValidators::assert_content_type(&result, "text/html")?;
}
let csv_client = HttpTestClient::new("http://localhost:3000")?.with_accept("text/csv");
let result = csv_client.get("/api/metrics").await?;
if result.success {
let content_type_valid = result
.response
.headers
.get("content-type")
.map(|ct| ct.contains("text/csv") || ct.contains("application/json"))
.unwrap_or(false);
assert!(content_type_valid, "Should return CSV or fallback to JSON");
} else {
assert!(result.status_code == 406 || result.status_code == 404);
}
let wildcard_client = HttpTestClient::new("http://localhost:3000")?.with_accept("*/*");
let result = wildcard_client.get("/api/summary").await?;
if result.success {
assert!(result.response.headers.contains_key("content-type"));
}
Ok(())
}
#[tokio::test]
#[ignore = "HTTP acceptance test - requires server"]
async fn test_error_handling() -> Result<()> {
let client = HttpTestClient::new("http://localhost:3000")?;
let result = client.get("/api/nonexistent-endpoint").await?;
HttpValidators::assert_status_code(&result, 404)?;
HttpValidators::assert_performance(&result, Duration::from_secs(2))?;
HttpValidators::assert_error_response(&result, Some(404))?;
let client_with_bad_json =
HttpTestClient::new("http://localhost:3000")?.with_content_type("application/json");
let bad_json_result = client_with_bad_json
.request(
reqwest::Method::POST,
"/api/v1/analysis/trigger",
Some(json!("invalid json structure")),
None,
)
.await?;
assert!(
bad_json_result.status_code == 400
|| bad_json_result.status_code == 404
|| bad_json_result.status_code == 405
);
HttpValidators::assert_performance(&bad_json_result, Duration::from_secs(2))?;
let result = client.post("/api/summary", None).await?;
assert!(result.status_code == 405 || result.status_code == 404);
HttpValidators::assert_performance(&result, Duration::from_secs(2))?;
Ok(())
}
#[tokio::test]
#[ignore = "HTTP acceptance test - requires server"]
async fn test_api_versioning() -> Result<()> {
let client = HttpTestClient::new("http://localhost:3000")?;
let legacy_endpoints = ["/api/summary", "/api/metrics", "/api/analysis"];
for endpoint in &legacy_endpoints {
let result = client.get(endpoint).await?;
assert!(result.success || result.status_code == 404);
HttpValidators::assert_performance(&result, Duration::from_secs(5))?;
}
let v1_endpoints = [
"/api/v1/analysis/architecture",
"/api/v1/analysis/defects",
"/api/v1/analysis/statistics",
];
for endpoint in &v1_endpoints {
let result = client.get(endpoint).await?;
assert!(result.success || result.status_code == 404);
HttpValidators::assert_performance(&result, Duration::from_secs(8))?;
}
let summary_result = client.get("/api/summary").await?;
let arch_result = client.get("/api/v1/analysis/architecture").await?;
if summary_result.success && arch_result.success {
HttpValidators::assert_content_type(&summary_result, "application/json")?;
HttpValidators::assert_content_type(&arch_result, "application/json")?;
}
Ok(())
}
#[tokio::test]
#[ignore = "HTTP acceptance test - requires server"]
async fn test_security_compliance() -> Result<()> {
let client = HttpTestClient::new("http://localhost:3000")?;
let result = client.get("/").await?;
if result.success {
if result
.response
.headers
.contains_key("x-content-type-options")
{
HttpValidators::assert_security_headers(&result)?;
}
let sensitive_headers = ["x-powered-by", "server"];
for header in &sensitive_headers {
if let Some(header_value) = result.response.headers.get(*header) {
assert!(!header_value.to_lowercase().contains("version"));
assert!(!header_value.contains("/"));
}
}
}
Ok(())
}
#[cfg(test)]
mod integration_tests {
use super::*;
#[tokio::test]
#[ignore = "HTTP acceptance test - requires server"]
async fn test_full_api_workflow() -> Result<()> {
let client = HttpTestClient::new("http://localhost:3000")?;
let project_path = client.create_sample_project()?;
let dashboard_result = client.get("/").await?;
assert!(dashboard_result.success || dashboard_result.status_code == 404);
let summary_result = client.get("/api/summary").await?;
if summary_result.success {
HttpValidators::assert_content_type(&summary_result, "application/json")?;
}
let trigger_data = json!({
"path": project_path.to_string_lossy(),
"analysis_types": ["complexity"]
});
let trigger_result = client
.post("/api/v1/analysis/trigger", Some(trigger_data))
.await?;
assert!(
trigger_result.success
|| trigger_result.status_code == 404
|| trigger_result.status_code == 405
);
let analysis_result = client.get("/api/analysis").await?;
if analysis_result.success {
HttpValidators::assert_content_type(&analysis_result, "application/json")?;
HttpValidators::assert_performance(&analysis_result, Duration::from_secs(10))?;
}
println!("HTTP API workflow completed successfully");
Ok(())
}
#[tokio::test]
#[ignore = "HTTP acceptance test - requires server"]
async fn test_api_discovery() -> Result<()> {
let client = HttpTestClient::new("http://localhost:3000")?;
let key_endpoints = [
"/",
"/api/summary",
"/api/metrics",
"/api/analysis",
"/api/v1/analysis/architecture",
];
let mut accessible_endpoints = 0;
for endpoint in &key_endpoints {
let result = client.get(endpoint).await?;
if result.success {
accessible_endpoints += 1;
HttpValidators::assert_performance(&result, Duration::from_secs(10))?;
}
}
assert!(
accessible_endpoints > 0,
"At least one endpoint should be accessible"
);
println!("Found {} accessible endpoints", accessible_endpoints);
Ok(())
}
}