mod e2e_common;
use amaters_server::config::ServerConfig;
use amaters_server::middleware::AdaptiveRateLimiter;
use amaters_server::server::{Server, ServerError};
use e2e_common::E2eTestContext;
#[tokio::test]
async fn test_server_startup_and_health_check() {
let ctx = E2eTestContext::new().await.expect("Server should start");
let key = amaters_core::types::Key::from_str("health_check_key");
let value = amaters_core::types::CipherBlob::new(vec![1, 2, 3]);
ctx.client
.set("default", &key, &value)
.await
.expect("Server should accept requests after startup");
let retrieved = ctx
.client
.get("default", &key)
.await
.expect("Server should serve requests");
assert!(retrieved.is_some());
ctx.cleanup().await;
}
#[tokio::test]
async fn test_graceful_shutdown() {
let ctx = E2eTestContext::new().await.expect("Server should start");
let key = amaters_core::types::Key::from_str("shutdown_test_key");
let value = amaters_core::types::CipherBlob::new(vec![10, 20, 30]);
ctx.client
.set("default", &key, &value)
.await
.expect("Set should succeed");
ctx.cleanup().await;
}
#[tokio::test]
async fn test_max_active_queries_enforced() {
let mut config = ServerConfig::default();
config.resource_limits.max_active_queries = 2;
let server = Server::new(config);
let _g1 = server.try_acquire_query().expect("Query 1 should succeed");
let _g2 = server.try_acquire_query().expect("Query 2 should succeed");
assert_eq!(server.active_query_count(), 2);
let result = server.try_acquire_query();
assert!(
matches!(result, Err(ServerError::ResourceExhausted(_))),
"Expected ResourceExhausted when limit exceeded, got {:?}",
result.err()
);
assert_eq!(server.active_query_count(), 2);
}
#[test]
fn test_per_client_connection_limit() {
let config = ServerConfig::default();
assert_eq!(config.resource_limits.max_connections_per_client, 10);
}
#[test]
fn test_adaptive_rate_limiter_reduces_on_errors() {
let limiter = AdaptiveRateLimiter::new(100);
assert_eq!(limiter.current_limit(), 100);
for _ in 0..50 {
limiter.record_error();
}
let reduced_limit = limiter.current_limit();
assert!(
reduced_limit < 100,
"Limit should decrease after many errors, got {}",
reduced_limit
);
}
#[test]
fn test_adaptive_rate_limiter_recovers() {
let limiter = AdaptiveRateLimiter::new(100);
for _ in 0..50 {
limiter.record_error();
}
let reduced = limiter.current_limit();
assert!(reduced < 100, "Should have reduced");
for _ in 0..200 {
limiter.record_success();
}
let recovered = limiter.current_limit();
assert!(
recovered > reduced,
"Limit should recover after successes: reduced={} recovered={}",
reduced,
recovered
);
}
#[test]
fn test_resource_limits_config() {
let config = ServerConfig::default();
assert_eq!(config.resource_limits.max_connections_per_client, 10);
assert_eq!(
config.resource_limits.max_requests_per_second_global,
10_000
);
assert!(config.resource_limits.max_memory_bytes.is_none());
assert_eq!(config.resource_limits.max_active_queries, 1000);
}
#[test]
fn test_circuit_cache_config() {
let config = ServerConfig::default();
assert_eq!(config.circuit_cache.max_entries, 1000);
assert_eq!(config.circuit_cache.ttl_secs, 300);
}
#[test]
fn test_timeout_config() {
let config = ServerConfig::default();
assert_eq!(config.timeouts.request_timeout_ms, 30_000);
assert_eq!(config.timeouts.idle_connection_timeout_ms, 60_000);
assert_eq!(config.timeouts.graceful_shutdown_timeout_ms, 5_000);
assert_eq!(config.timeouts.keep_alive_interval_ms, 15_000);
assert!(config.validate().is_ok());
}