use ri::gateway::{
RiGatewayConfig,
RiGatewayRequest,
RiGatewayResponse,
RiGateway,
RiRoute,
RiRouter,
RiMiddleware,
RiMiddlewareChain,
RiLoadBalancer,
RiLoadBalancerStrategy,
RiRateLimiter,
RiRateLimitConfig,
RiCircuitBreaker,
RiCircuitBreakerConfig,
};
use ri::gateway::load_balancer::RiBackendServer;
use ri::prelude::RiResult;
use std::collections::HashMap;
use std::sync::Arc;
#[test]
fn test_gateway_config_default() {
let config = RiGatewayConfig::default();
assert_eq!(config.listen_address, "0.0.0.0");
assert_eq!(config.listen_port, 8080);
assert_eq!(config.max_connections, 10000);
assert_eq!(config.request_timeout_seconds, 30);
assert!(config.enable_rate_limiting);
assert!(config.enable_circuit_breaker);
assert!(config.enable_load_balancing);
assert!(config.cors_enabled);
assert_eq!(config.cors_origins, vec!["*".to_string()]);
assert!(config.enable_logging);
assert_eq!(config.log_level, "info");
}
#[test]
fn test_gateway_request_new() {
let method = "GET".to_string();
let path = "/test".to_string();
let headers = std::collections::HashMap::new();
let query_params = std::collections::HashMap::new();
let body = None::<Vec<u8>>;
let remote_addr = "127.0.0.1:12345".to_string();
let request = RiGatewayRequest::new(
method.clone(),
path.clone(),
headers.clone(),
query_params.clone(),
body.clone(),
remote_addr.clone(),
);
assert!(!request.id.is_empty());
assert_eq!(request.method, method);
assert_eq!(request.path, path);
assert_eq!(request.headers, headers);
assert_eq!(request.query_params, query_params);
assert_eq!(request.body, body);
assert_eq!(request.remote_addr, remote_addr);
}
#[test]
fn test_gateway_response_new() {
let status_code = 200;
let body = b"test_body".to_vec();
let request_id = "test_request_id".to_string();
let response = RiGatewayResponse::new(status_code, body.clone(), request_id.clone());
assert_eq!(response.status_code, status_code);
assert_eq!(response.body, body);
assert_eq!(response.request_id, request_id);
assert!(response.headers.contains_key("Content-Type"));
assert!(response.headers.contains_key("X-Request-ID"));
}
#[test]
fn test_gateway_response_with_header() {
let status_code = 200;
let body = b"test_body".to_vec();
let request_id = "test_request_id".to_string();
let response = RiGatewayResponse::new(status_code, body.clone(), request_id.clone())
.with_header("Custom-Header".to_string(), "Custom-Value".to_string());
assert_eq!(response.headers.get("Custom-Header"), Some(&"Custom-Value".to_string()));
}
#[test]
fn test_gateway_response_json() {
let status_code = 200;
let request_id = "test_request_id".to_string();
let data = serde_json::json!({"key": "value"});
let response = RiGatewayResponse::json(status_code, &data, request_id.clone()).unwrap();
assert_eq!(response.status_code, status_code);
assert_eq!(response.request_id, request_id);
assert!(response.headers.contains_key("Content-Type"));
assert_eq!(response.headers.get("Content-Type"), Some(&"application/json".to_string()));
}
#[test]
fn test_gateway_response_error() {
let status_code = 404;
let message = "Not Found".to_string();
let request_id = "test_request_id".to_string();
let response = RiGatewayResponse::error(status_code, message.clone(), request_id.clone());
assert_eq!(response.status_code, status_code);
assert_eq!(response.request_id, request_id);
assert!(response.headers.contains_key("Content-Type"));
assert!(response.body.len() > 0);
}
#[tokio::test]
async fn test_gateway_new() {
let gateway = RiGateway::new();
assert_eq!(gateway.router().route_count(), 0);
assert_eq!(gateway.middleware_chain().len(), 0);
}
#[tokio::test]
async fn test_gateway_router() {
let router = RiRouter::new();
let handler = Arc::new(|request: RiGatewayRequest| {
Box::pin(async move {
Ok(RiGatewayResponse::new(
200,
b"test_response".to_vec(),
request.id,
))
}) as std::pin::Pin<Box<dyn std::future::Future<Output = RiResult<RiGatewayResponse>> + Send>>
});
let route = RiRoute::new(
"GET".to_string(),
"/test".to_string(),
handler,
);
router.add_route(route);
assert_eq!(router.route_count(), 1);
}
#[tokio::test]
async fn test_gateway_middleware_chain() {
struct TestMiddleware;
#[async_trait::async_trait]
impl RiMiddleware for TestMiddleware {
async fn execute(
&self,
request: &mut RiGatewayRequest,
) -> RiResult<()> {
request
.headers
.insert("X-Custom-Middleware".to_string(), "applied".to_string());
Ok(())
}
fn name(&self) -> &'static str {
"TestMiddleware"
}
}
let mut middleware_chain = RiMiddlewareChain::new();
middleware_chain.add(Arc::new(TestMiddleware));
let mut request = RiGatewayRequest::new(
"GET".to_string(),
"/test".to_string(),
HashMap::new(),
HashMap::new(),
None,
"127.0.0.1:12345".to_string(),
);
middleware_chain.execute(&mut request).await.unwrap();
assert_eq!(
request.headers.get("X-Custom-Middleware"),
Some(&"applied".to_string())
);
assert_eq!(middleware_chain.len(), 1);
}
#[tokio::test]
async fn test_gateway_handle_request() {
let gateway = RiGateway::new();
let router = gateway.router();
let handler = Arc::new(|request: RiGatewayRequest| {
Box::pin(async move {
Ok(RiGatewayResponse::new(
200,
b"test_response".to_vec(),
request.id,
))
}) as std::pin::Pin<Box<dyn std::future::Future<Output = RiResult<RiGatewayResponse>> + Send>>
});
let route = RiRoute::new(
"GET".to_string(),
"/test".to_string(),
handler,
);
router.add_route(route);
let request = RiGatewayRequest::new(
"GET".to_string(),
"/test".to_string(),
std::collections::HashMap::new(),
std::collections::HashMap::new(),
None,
"127.0.0.1:12345".to_string(),
);
let response = gateway.handle_request(request).await;
assert_eq!(response.status_code, 200);
assert_eq!(response.body, b"test_response".to_vec());
}
#[tokio::test]
async fn test_gateway_handle_request_not_found() {
let gateway = RiGateway::new();
let request = RiGatewayRequest::new(
"GET".to_string(),
"/non_existent_route".to_string(),
std::collections::HashMap::new(),
std::collections::HashMap::new(),
None,
"127.0.0.1:12345".to_string(),
);
let response = gateway.handle_request(request).await;
assert_eq!(response.status_code, 404);
}
#[tokio::test]
async fn test_load_balancer_new() {
let load_balancer = RiLoadBalancer::new(RiLoadBalancerStrategy::RoundRobin);
let server1 = RiBackendServer::new(
"server1".to_string(),
"http://localhost:8001".to_string(),
);
let server2 = RiBackendServer::new(
"server2".to_string(),
"http://localhost:8002".to_string(),
);
load_balancer.add_server(server1).await;
load_balancer.add_server(server2).await;
let targets = load_balancer.get_healthy_servers().await;
assert_eq!(targets.len(), 2);
let target = load_balancer.select_server(None).await.unwrap();
assert!(target.url.starts_with("http://localhost"));
}
#[tokio::test]
async fn test_rate_limiter_new() {
let config = RiRateLimitConfig {
requests_per_second: 100,
burst_size: 200,
window_seconds: 1,
};
let rate_limiter = RiRateLimiter::new(config);
let request = RiGatewayRequest::new(
"GET".to_string(),
"/test".to_string(),
std::collections::HashMap::new(),
std::collections::HashMap::new(),
None,
"127.0.0.1:12345".to_string(),
);
let allowed = rate_limiter.check_request(&request).await;
assert!(allowed);
}
#[tokio::test]
async fn test_circuit_breaker_new() {
let config = RiCircuitBreakerConfig {
failure_threshold: 5,
success_threshold: 3,
timeout_seconds: 30,
monitoring_period_seconds: 30,
};
let circuit_breaker = RiCircuitBreaker::new(config);
let allowed = circuit_breaker.allow_request().await;
assert!(allowed);
circuit_breaker.record_success().await;
circuit_breaker.record_failure().await;
}