Skip to main content

mockforge_smtp/
protocol_server.rs

1//! Unified protocol server implementation for the SMTP mock server.
2
3use std::sync::Arc;
4
5use async_trait::async_trait;
6use mockforge_core::protocol_abstraction::Protocol;
7use mockforge_core::protocol_server::MockProtocolServer;
8
9use crate::server::SmtpServer;
10use crate::spec_registry::SmtpSpecRegistry;
11use crate::SmtpConfig;
12
13/// A `MockProtocolServer` wrapper around [`SmtpServer`].
14///
15/// Constructs the SMTP server and spec registry, then delegates to
16/// [`SmtpServer::start`] with shutdown-signal integration.
17pub struct SmtpMockServer {
18    config: SmtpConfig,
19}
20
21impl SmtpMockServer {
22    /// Create a new `SmtpMockServer` with the given configuration.
23    pub fn new(config: SmtpConfig) -> Self {
24        Self { config }
25    }
26}
27
28#[async_trait]
29impl MockProtocolServer for SmtpMockServer {
30    fn protocol(&self) -> Protocol {
31        Protocol::Smtp
32    }
33
34    async fn start(
35        &self,
36        mut shutdown: tokio::sync::watch::Receiver<()>,
37    ) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
38        let spec_registry = Arc::new(SmtpSpecRegistry::new());
39        let server = SmtpServer::new(self.config.clone(), spec_registry)
40            .map_err(|e| Box::new(e) as Box<dyn std::error::Error + Send + Sync>)?;
41
42        tokio::select! {
43            result = server.start() => {
44                result.map_err(|e| Box::new(e) as Box<dyn std::error::Error + Send + Sync>)
45            }
46            _ = shutdown.changed() => {
47                tracing::info!("Shutting down SMTP server on port {}", self.config.port);
48                Ok(())
49            }
50        }
51    }
52
53    fn port(&self) -> u16 {
54        self.config.port
55    }
56
57    fn description(&self) -> String {
58        format!("SMTP server on {}:{}", self.config.host, self.config.port)
59    }
60}
61
62#[cfg(test)]
63mod tests {
64    use super::*;
65
66    #[test]
67    fn test_smtp_mock_server_protocol() {
68        let server = SmtpMockServer::new(SmtpConfig::default());
69        assert_eq!(server.protocol(), Protocol::Smtp);
70    }
71
72    #[test]
73    fn test_smtp_mock_server_port() {
74        let server = SmtpMockServer::new(SmtpConfig::default());
75        assert_eq!(server.port(), server.config.port);
76    }
77
78    #[test]
79    fn test_smtp_mock_server_description() {
80        let config = SmtpConfig {
81            host: "127.0.0.1".to_string(),
82            port: 2525,
83            ..Default::default()
84        };
85        let server = SmtpMockServer::new(config);
86        assert_eq!(server.description(), "SMTP server on 127.0.0.1:2525");
87    }
88}