use axum::http::{HeaderMap, Method, Uri};
use mockforge_core::priority_handler::{PriorityHttpHandler, SimpleMockGenerator};
use mockforge_core::{RecordReplayHandler, RequestFingerprint};
use std::sync::Arc;
use tempfile::TempDir;
fn create_test_handler() -> PriorityHttpHandler {
let temp_dir = TempDir::new().unwrap();
let fixtures_dir = temp_dir.path().to_path_buf();
let record_replay = RecordReplayHandler::new(fixtures_dir, true, true, false);
let mock_generator =
Box::new(SimpleMockGenerator::new(200, r#"{"message": "mock response"}"#.to_string()));
PriorityHttpHandler::new(
record_replay,
None, None, Some(mock_generator),
)
}
#[tokio::test]
async fn test_priority_handler_empty_state() {
let handler = create_test_handler();
let method = Method::GET;
let uri = Uri::from_static("/api/test");
let headers = HeaderMap::new();
let result = handler.process_request(&method, &uri, &headers, None).await;
assert!(result.is_ok());
let response = result.unwrap();
assert_eq!(response.source.priority, mockforge_core::ResponsePriority::Mock);
}
#[tokio::test]
async fn test_priority_handler_invalid_uri() {
let handler = create_test_handler();
let method = Method::GET;
let uri = Uri::from_static("/api/test");
let headers = HeaderMap::new();
let result = handler.process_request(&method, &uri, &headers, None).await;
assert!(result.is_ok());
}
#[tokio::test]
async fn test_priority_handler_empty_body() {
let handler = create_test_handler();
let method = Method::POST;
let uri = Uri::from_static("/api/test");
let headers = HeaderMap::new();
let result = handler.process_request(&method, &uri, &headers, Some(&[])).await;
assert!(result.is_ok());
}
#[tokio::test]
async fn test_priority_handler_large_body() {
let handler = create_test_handler();
let method = Method::POST;
let uri = Uri::from_static("/api/test");
let headers = HeaderMap::new();
let large_body = vec![0u8; 10000];
let result = handler.process_request(&method, &uri, &headers, Some(&large_body)).await;
assert!(result.is_ok());
}
#[test]
fn test_request_fingerprint_edge_cases() {
let method = Method::GET;
let uri = Uri::from_static("/");
let headers = HeaderMap::new();
let fingerprint = RequestFingerprint::new(method.clone(), &uri, &headers, None);
assert_eq!(fingerprint.path, "/");
let uri = Uri::from_static("/api/test?a=1&b=2");
let fingerprint = RequestFingerprint::new(method.clone(), &uri, &headers, None);
assert_eq!(fingerprint.path, "/api/test");
assert!(fingerprint.query.contains("a=1"));
assert!(fingerprint.query.contains("b=2"));
let body = b"test body";
let fingerprint1 = RequestFingerprint::new(method.clone(), &uri, &headers, Some(body));
let fingerprint2 = RequestFingerprint::new(method.clone(), &uri, &headers, Some(body));
assert_eq!(fingerprint1.body_hash, fingerprint2.body_hash);
let body2 = b"different body";
let fingerprint3 = RequestFingerprint::new(method, &uri, &headers, Some(body2));
assert_ne!(fingerprint1.body_hash, fingerprint3.body_hash);
}
#[test]
fn test_request_fingerprint_special_characters() {
let method = Method::GET;
let headers = HeaderMap::new();
let uri = Uri::from_static("/api/test%20path");
let fingerprint = RequestFingerprint::new(method.clone(), &uri, &headers, None);
assert_eq!(fingerprint.path, "/api/test%20path");
let uri = Uri::from_static("/api/test?param=value%20with%20spaces");
let fingerprint = RequestFingerprint::new(method, &uri, &headers, None);
assert!(fingerprint.query.contains("param=value%20with%20spaces"));
}
#[test]
fn test_request_fingerprint_all_methods() {
let headers = HeaderMap::new();
let uri = Uri::from_static("/api/test");
let methods = vec![
Method::GET,
Method::POST,
Method::PUT,
Method::DELETE,
Method::PATCH,
Method::HEAD,
Method::OPTIONS,
];
for method in methods {
let method_str = method.to_string();
let fingerprint = RequestFingerprint::new(method, &uri, &headers, None);
assert_eq!(fingerprint.method, method_str);
}
}
#[test]
fn test_request_fingerprint_tags() {
let headers = HeaderMap::new();
let method = Method::GET;
let uri = Uri::from_static("/api/users");
let fingerprint = RequestFingerprint::new(method, &uri, &headers, None);
let tags = fingerprint.tags();
assert!(tags.contains(&"api".to_string()));
assert!(tags.contains(&"users".to_string()));
assert!(tags.contains(&"get".to_string()));
let method = Method::GET;
let uri = Uri::from_static("/api/users/{id}/posts");
let fingerprint = RequestFingerprint::new(method, &uri, &headers, None);
let tags = fingerprint.tags();
assert!(tags.contains(&"api".to_string()));
assert!(tags.contains(&"users".to_string()));
assert!(tags.contains(&"posts".to_string()));
assert!(!tags.iter().any(|t| t.starts_with('{')));
}
#[test]
fn test_request_fingerprint_display() {
let method = Method::POST;
let uri = Uri::from_static("/api/test?param=value");
let mut headers = HeaderMap::new();
headers.insert("authorization", "Bearer token123".parse().unwrap());
headers.insert("content-type", "application/json".parse().unwrap());
let fingerprint = RequestFingerprint::new(method, &uri, &headers, None);
let display = fingerprint.to_string();
assert!(display.contains("POST"));
assert!(display.contains("/api/test"));
assert!(display.contains("param=value"));
assert!(display.contains("authorization"));
assert!(display.contains("content-type"));
}
#[test]
fn test_request_fingerprint_hash_consistency() {
let method = Method::GET;
let uri = Uri::from_static("/api/test");
let headers = HeaderMap::new();
let fingerprint1 = RequestFingerprint::new(method.clone(), &uri, &headers, None);
let fingerprint2 = RequestFingerprint::new(method, &uri, &headers, None);
assert_eq!(fingerprint1.to_hash(), fingerprint2.to_hash());
}
#[tokio::test]
async fn test_priority_handler_custom_fixture_no_match() {
use mockforge_core::CustomFixtureLoader;
let temp_dir = TempDir::new().unwrap();
let fixtures_dir = temp_dir.path().to_path_buf();
let record_replay = RecordReplayHandler::new(fixtures_dir.clone(), true, true, false);
let mock_generator =
Box::new(SimpleMockGenerator::new(200, r#"{"message": "mock response"}"#.to_string()));
let loader = Arc::new(CustomFixtureLoader::new(fixtures_dir, true));
let handler = PriorityHttpHandler::new(record_replay, None, None, Some(mock_generator))
.with_custom_fixture_loader(loader);
let method = Method::GET;
let uri = Uri::from_static("/api/nonexistent");
let headers = HeaderMap::new();
let result = handler.process_request(&method, &uri, &headers, None).await;
assert!(result.is_ok());
let response = result.unwrap();
assert_eq!(response.source.priority, mockforge_core::ResponsePriority::Mock);
}
#[tokio::test]
async fn test_priority_handler_error_recovery() {
let handler = create_test_handler();
let method = Method::GET;
let uri = Uri::from_static("/api/test");
let mut headers = HeaderMap::new();
headers.insert("x-custom", "value-with-special-chars-!@#$%".parse().unwrap());
let result = handler.process_request(&method, &uri, &headers, None).await;
assert!(result.is_ok());
}
#[test]
fn test_request_fingerprint_unicode() {
let method = Method::GET;
let headers = HeaderMap::new();
let uri = Uri::from_static("/api/test%E2%98%BA"); let fingerprint = RequestFingerprint::new(method, &uri, &headers, None);
assert_eq!(fingerprint.path, "/api/test%E2%98%BA");
}
#[test]
fn test_request_fingerprint_empty_query() {
let method = Method::GET;
let uri = Uri::from_static("/api/test");
let headers = HeaderMap::new();
let fingerprint = RequestFingerprint::new(method, &uri, &headers, None);
assert_eq!(fingerprint.query, "");
}
#[test]
fn test_request_fingerprint_duplicate_query() {
let method = Method::GET;
let uri = Uri::from_static("/api/test?param=1¶m=2");
let headers = HeaderMap::new();
let fingerprint = RequestFingerprint::new(method, &uri, &headers, None);
assert!(fingerprint.query.contains("param=1"));
assert!(fingerprint.query.contains("param=2"));
}
#[tokio::test]
async fn test_priority_handler_minimal_config() {
let handler = create_test_handler();
let method = Method::GET;
let uri = Uri::from_static("/api/test");
let headers = HeaderMap::new();
let result = handler.process_request(&method, &uri, &headers, None).await;
assert!(result.is_ok());
let response = result.unwrap();
assert_eq!(response.source.priority, mockforge_core::ResponsePriority::Mock);
}
#[test]
fn test_request_fingerprint_header_combinations() {
let method = Method::GET;
let uri = Uri::from_static("/api/test");
let headers = HeaderMap::new();
let fingerprint = RequestFingerprint::new(method.clone(), &uri, &headers, None);
assert!(fingerprint.headers.is_empty());
let mut headers = HeaderMap::new();
headers.insert("authorization", "Bearer token".parse().unwrap());
headers.insert("content-type", "application/json".parse().unwrap());
headers.insert("accept", "application/json".parse().unwrap());
let fingerprint = RequestFingerprint::new(method, &uri, &headers, None);
assert_eq!(fingerprint.headers.len(), 3);
assert_eq!(fingerprint.headers.get("authorization"), Some(&"Bearer token".to_string()));
assert_eq!(fingerprint.headers.get("content-type"), Some(&"application/json".to_string()));
assert_eq!(fingerprint.headers.get("accept"), Some(&"application/json".to_string()));
}
#[test]
fn test_request_fingerprint_non_important_headers() {
let method = Method::GET;
let uri = Uri::from_static("/api/test");
let mut headers = HeaderMap::new();
headers.insert("x-custom-header", "custom-value".parse().unwrap());
let fingerprint = RequestFingerprint::new(method, &uri, &headers, None);
assert!(!fingerprint.headers.contains_key("x-custom-header"));
}
#[test]
fn test_request_fingerprint_invalid_header_values() {
let method = Method::GET;
let uri = Uri::from_static("/api/test");
let mut headers = HeaderMap::new();
headers.insert("authorization", "Bearer token-with-special!@#chars".parse().unwrap());
let fingerprint = RequestFingerprint::new(method, &uri, &headers, None);
assert!(fingerprint.headers.contains_key("authorization"));
assert_eq!(
fingerprint.headers.get("authorization"),
Some(&"Bearer token-with-special!@#chars".to_string())
);
}