Files
servme/tests/integration_tests.rs
T

263 lines
7.6 KiB
Rust

//! Integration tests for the Servme HTTP framework.
//!
//! These tests verify the end-to-end functionality of the server
//! including middleware chains and request handling.
use servme::{
ApiKeyMiddleware, Claims, IpFilterMiddleware, Responder, ServerBuilder, ServerConfig,
ServerError, UrlExtract,
};
use std::net::IpAddr;
// ============================================================================
// Server Configuration Tests
// ============================================================================
#[test]
fn test_server_builder_default_config() {
let builder = ServerBuilder::new();
// Verify default values
assert_eq!(builder.config.ip, "127.0.0.1");
assert_eq!(builder.config.port, 8080);
assert!(builder.middlewares.is_empty());
assert!(builder.data.is_none());
}
#[test]
fn test_server_builder_with_address() {
let builder = ServerBuilder::new().address("0.0.0.0", 3000);
assert_eq!(builder.config.ip, "0.0.0.0");
assert_eq!(builder.config.port, 3000);
}
#[test]
fn test_server_builder_chaining() {
let server = ServerBuilder::new()
.address("127.0.0.1", 8080)
.add_api_key_middleware("test-key")
.build();
assert_eq!(server.config.ip, "127.0.0.1");
assert_eq!(server.config.port, 8080);
assert_eq!(server.middlewares.len(), 1);
}
#[test]
fn test_server_config_default() {
let config = ServerConfig::default();
assert_eq!(config.ip, "127.0.0.1");
assert_eq!(config.port, 8080);
}
// ============================================================================
// Responder Tests
// ============================================================================
#[test]
fn test_responder_ok() {
let result = Responder::ok("Hello");
assert!(result.is_ok());
let response = result.unwrap();
assert_eq!(response.status(), http::StatusCode::OK);
}
#[test]
fn test_responder_json() {
#[derive(serde::Serialize)]
struct TestData {
name: String,
value: i32,
}
let data = TestData {
name: "test".to_string(),
value: 42,
};
let result = Responder::json(&data);
assert!(result.is_ok());
let response = result.unwrap();
assert_eq!(response.status(), http::StatusCode::OK);
assert_eq!(
response.headers().get("content-type").unwrap(),
"application/json"
);
}
#[test]
fn test_responder_redirect() {
let result = Responder::redirect("/new-location");
assert!(result.is_ok());
let response = result.unwrap();
assert_eq!(response.status(), http::StatusCode::SEE_OTHER);
assert_eq!(response.headers().get("location").unwrap(), "/new-location");
}
#[test]
fn test_responder_redirect_empty_fails() {
let result = Responder::redirect("");
assert!(result.is_err());
}
#[test]
fn test_responder_status_codes() {
assert!(Responder::not_found().is_ok());
assert!(Responder::unauthorized().is_ok());
assert!(Responder::forbidden().is_ok());
assert!(Responder::bad_request("bad").is_ok());
assert!(Responder::no_content().is_ok());
assert!(Responder::internal_error("error").is_ok());
let response = Responder::not_found().unwrap();
assert_eq!(response.status(), http::StatusCode::NOT_FOUND);
let response = Responder::unauthorized().unwrap();
assert_eq!(response.status(), http::StatusCode::UNAUTHORIZED);
}
// ============================================================================
// Middleware Tests
// ============================================================================
#[test]
fn test_api_key_middleware_creation() {
let middleware = ApiKeyMiddleware::new("test-key");
// Verify it's properly constructed - use is_invalid_key to check
assert!(!middleware.is_invalid_key("test-key"));
assert!(middleware.is_invalid_key("wrong-key"));
}
#[test]
fn test_ip_filter_middleware_validation() {
// Valid IPs should work
let result = IpFilterMiddleware::new(vec![], false);
assert!(result.is_ok());
let result = IpFilterMiddleware::new(
vec!["192.168.1.1".to_string(), "10.0.0.1".to_string()],
false,
);
assert!(result.is_ok());
// Invalid IP should fail
let result = IpFilterMiddleware::new(vec!["not-an-ip".to_string()], false);
assert!(result.is_err());
}
#[test]
fn test_ip_filter_authorization() {
// Test with checked middleware for valid IPs
let middleware = IpFilterMiddleware::new(vec!["192.168.1.100".to_string()], false).unwrap();
let allowed_ip: IpAddr = "192.168.1.100".parse().unwrap();
let denied_ip: IpAddr = "192.168.1.200".parse().unwrap();
assert!(middleware.is_authorized(&allowed_ip));
assert!(!middleware.is_authorized(&denied_ip));
}
#[test]
fn test_ip_filter_ipv6() {
let middleware = IpFilterMiddleware::new(vec!["::1".to_string()], false).unwrap();
let ipv6_local: IpAddr = "::1".parse().unwrap();
let ipv6_other: IpAddr = "::2".parse().unwrap();
assert!(middleware.is_authorized(&ipv6_local));
assert!(!middleware.is_authorized(&ipv6_other));
}
// ============================================================================
// URL Extract Tests
// ============================================================================
#[test]
fn test_url_extract_params() {
let uri: http::Uri = "/api?name=test&value=42".parse().unwrap();
let extractor = UrlExtract::new(&uri);
assert_eq!(extractor.param_str("name"), Some("test".to_string()));
assert_eq!(extractor.param_i64("value"), Some(42));
}
#[test]
fn test_url_extract_missing_param() {
let uri: http::Uri = "/api".parse().unwrap();
let extractor = UrlExtract::new(&uri);
assert_eq!(extractor.param_str("missing"), None);
}
// ============================================================================
// Claims Tests
// ============================================================================
#[test]
fn test_claims_is_expired() {
let claims = Claims {
sub: "user123".to_string(),
exp: 1000, // Very old timestamp
};
assert!(claims.is_expired(2000)); // Current time > exp
assert!(!claims.is_expired(500)); // Current time < exp
}
#[test]
fn test_claims_username() {
let claims = Claims {
sub: "testuser".to_string(),
exp: 9999999999,
};
assert_eq!(claims.username(), "testuser");
}
// ============================================================================
// Error Handling Tests
// ============================================================================
#[test]
fn test_server_error_display() {
let error = ServerError::bind(
"127.0.0.1:8080",
std::io::Error::new(std::io::ErrorKind::AddrInUse, "Address already in use"),
);
let display = format!("{}", error);
assert!(display.contains("Failed to bind"));
assert!(display.contains("127.0.0.1:8080"));
}
#[test]
fn test_server_error_validation() {
let error = ServerError::validation("field", "must not be empty");
let display = format!("{}", error);
assert!(display.contains("Validation failed"));
assert!(display.contains("field"));
}
// ============================================================================
// Constants Tests
// ============================================================================
#[test]
fn test_constants_values() {
use servme::constants::{
BEARER_PREFIX, DEFAULT_HOST, DEFAULT_PORT, FILE_EXTENSIONS, JWT_COOKIE_NAME,
};
assert_eq!(DEFAULT_HOST, "127.0.0.1");
assert_eq!(DEFAULT_PORT, 8080);
assert_eq!(JWT_COOKIE_NAME, "access_token");
assert_eq!(BEARER_PREFIX, "Bearer ");
assert!(FILE_EXTENSIONS.contains(&".json"));
assert!(FILE_EXTENSIONS.contains(&".html"));
}