elif_http/
tests.rs

1//! Tests for HTTP server functionality
2
3#[cfg(test)]
4mod tests {
5    use super::*;
6    use crate::{HttpConfig, MinimalHttpServer};
7    use elif_core::{
8        Container,
9        container::test_implementations::*,
10        app_config::{AppConfigTrait},
11    };
12    use std::sync::Arc;
13
14    fn create_test_container() -> Arc<Container> {
15        let config = Arc::new(create_test_config());
16        let database = Arc::new(TestDatabase::new()) as Arc<dyn elif_core::DatabaseConnection>;
17        
18        Container::builder()
19            .config(config)
20            .database(database)
21            .build()
22            .unwrap()
23            .into()
24    }
25
26    #[test]
27    fn test_http_config_defaults() {
28        let config = HttpConfig::default();
29        
30        assert_eq!(config.request_timeout_secs, 30);
31        assert_eq!(config.keep_alive_timeout_secs, 75);
32        assert_eq!(config.max_request_size, 16 * 1024 * 1024);
33        assert!(config.enable_tracing);
34        assert_eq!(config.health_check_path, "/health");
35        assert_eq!(config.shutdown_timeout_secs, 10);
36    }
37
38    #[test]
39    fn test_http_config_from_env() {
40        std::env::remove_var("HTTP_REQUEST_TIMEOUT");
41        std::env::remove_var("HTTP_KEEP_ALIVE_TIMEOUT");
42        
43        let config = HttpConfig::from_env().unwrap();
44        config.validate().unwrap();
45        
46        // Test duration helpers
47        assert_eq!(config.request_timeout().as_secs(), 30);
48        assert_eq!(config.keep_alive_timeout().as_secs(), 75);
49        assert_eq!(config.shutdown_timeout().as_secs(), 10);
50    }
51
52    #[test]
53    fn test_http_config_validation() {
54        let mut config = HttpConfig::default();
55        assert!(config.validate().is_ok());
56
57        // Test invalid request timeout
58        config.request_timeout_secs = 0;
59        assert!(config.validate().is_err());
60
61        // Test invalid health check path
62        config = HttpConfig::default();
63        config.health_check_path = "no-slash".to_string();
64        assert!(config.validate().is_err());
65
66        config.health_check_path = "".to_string();
67        assert!(config.validate().is_err());
68    }
69
70    #[test]
71    fn test_minimal_server_creation() {
72        let container = create_test_container();
73        let http_config = HttpConfig::default();
74
75        let server = MinimalHttpServer::new(container, http_config);
76        assert!(server.is_ok());
77    }
78
79    #[test]
80    fn test_minimal_server_with_invalid_address() {
81        // Create container with invalid server config
82        let mut app_config = create_test_config();
83        app_config.server.host = "999.999.999.999".to_string(); // Invalid IP
84        let config_arc = Arc::new(app_config);
85        
86        let database = Arc::new(TestDatabase::new()) as Arc<dyn elif_core::DatabaseConnection>;
87        let container = Container::builder()
88            .config(config_arc)
89            .database(database)
90            .build()
91            .unwrap();
92
93        let http_config = HttpConfig::default();
94        let result = MinimalHttpServer::new(Arc::new(container), http_config);
95        
96        assert!(result.is_err());
97        if let Err(e) = result {
98            assert!(e.to_string().contains("Invalid server address"));
99        }
100    }
101
102    #[tokio::test]
103    async fn test_health_check_endpoint() {
104        use crate::minimal_server::minimal_health_check;
105        
106        let response = minimal_health_check().await;
107        let value = response.0;
108        
109        assert_eq!(value["status"], "healthy");
110        assert_eq!(value["version"], "0.1.0");
111        assert_eq!(value["server"], "minimal");
112        assert!(value["timestamp"].is_string());
113    }
114
115    #[test]
116    fn test_http_error_types() {
117        use crate::error::HttpError;
118        use axum::http::StatusCode;
119        
120        let startup_error = HttpError::startup("Failed to bind");
121        assert_eq!(startup_error.status_code(), StatusCode::INTERNAL_SERVER_ERROR);
122        assert_eq!(startup_error.error_code(), "SERVER_STARTUP_FAILED");
123        
124        let timeout_error = HttpError::RequestTimeout;
125        assert_eq!(timeout_error.status_code(), StatusCode::REQUEST_TIMEOUT);
126        assert_eq!(timeout_error.error_code(), "REQUEST_TIMEOUT");
127        
128        let bad_request = HttpError::bad_request("Invalid input");
129        assert_eq!(bad_request.status_code(), StatusCode::BAD_REQUEST);
130        assert_eq!(bad_request.error_code(), "BAD_REQUEST");
131    }
132
133    #[test]
134    fn test_error_conversions() {
135        use crate::error::HttpError;
136        use elif_core::app_config::ConfigError;
137        
138        // Test ConfigError conversion
139        let config_error = ConfigError::MissingEnvVar {
140            var: "TEST_VAR".to_string(),
141        };
142        let http_error: HttpError = config_error.into();
143        assert!(matches!(http_error, HttpError::ConfigError { .. }));
144        
145        // Test IO error conversion
146        let io_error = std::io::Error::new(std::io::ErrorKind::PermissionDenied, "Access denied");
147        let http_error: HttpError = io_error.into();
148        assert!(matches!(http_error, HttpError::InternalError { .. }));
149    }
150}