Skip to main content

mockforge_http/
protocol_server.rs

1//! Unified protocol server implementation for the HTTP mock server.
2
3use async_trait::async_trait;
4use axum::Router;
5use mockforge_core::config::HttpTlsConfig;
6use mockforge_core::protocol_abstraction::Protocol;
7use mockforge_core::protocol_server::MockProtocolServer;
8
9/// A `MockProtocolServer` wrapper around the HTTP server startup.
10///
11/// Wraps [`crate::serve_router_with_tls`] with shutdown-signal integration.
12/// The caller must supply a pre-built [`Router`] — this struct does not
13/// construct one itself, because router construction depends on OpenAPI
14/// specs, middleware, and CLI flags that are outside this crate's scope.
15pub struct HttpMockServer {
16    port: u16,
17    router: Router,
18    tls_config: Option<HttpTlsConfig>,
19}
20
21impl HttpMockServer {
22    /// Create a new `HttpMockServer` with the given configuration.
23    pub fn new(port: u16, router: Router, tls_config: Option<HttpTlsConfig>) -> Self {
24        Self {
25            port,
26            router,
27            tls_config,
28        }
29    }
30}
31
32#[async_trait]
33impl MockProtocolServer for HttpMockServer {
34    fn protocol(&self) -> Protocol {
35        Protocol::Http
36    }
37
38    async fn start(
39        &self,
40        mut shutdown: tokio::sync::watch::Receiver<()>,
41    ) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
42        // Router is Clone (axum::Router is cheaply cloneable)
43        let router = self.router.clone();
44        let port = self.port;
45        let tls_config = self.tls_config.clone();
46
47        tokio::select! {
48            result = crate::serve_router_with_tls(port, router, tls_config) => {
49                result
50            }
51            _ = shutdown.changed() => {
52                tracing::info!("Shutting down HTTP server on port {}", port);
53                Ok(())
54            }
55        }
56    }
57
58    fn port(&self) -> u16 {
59        self.port
60    }
61
62    fn description(&self) -> String {
63        format!("HTTP server on port {}", self.port)
64    }
65}
66
67#[cfg(test)]
68mod tests {
69    use super::*;
70
71    #[test]
72    fn test_http_mock_server_protocol() {
73        let server = HttpMockServer::new(3000, Router::new(), None);
74        assert_eq!(server.protocol(), Protocol::Http);
75    }
76
77    #[test]
78    fn test_http_mock_server_port() {
79        let server = HttpMockServer::new(8080, Router::new(), None);
80        assert_eq!(server.port(), 8080);
81    }
82
83    #[test]
84    fn test_http_mock_server_description() {
85        let server = HttpMockServer::new(3000, Router::new(), None);
86        assert_eq!(server.description(), "HTTP server on port 3000");
87    }
88}