Skip to main content

mockforge_smtp/
lib.rs

1//! SMTP server mocking for MockForge
2//!
3//! This crate provides SMTP server functionality for MockForge, allowing you to mock
4//! email servers for testing purposes.
5//!
6//! # Example
7//!
8//! ```no_run
9//! use mockforge_smtp::{SmtpConfig, SmtpServer, SmtpSpecRegistry};
10//! use std::sync::Arc;
11//!
12//! #[tokio::main]
13//! async fn main() -> Result<(), Box<dyn std::error::Error>> {
14//!     let config = SmtpConfig::default();
15//!     let registry = Arc::new(SmtpSpecRegistry::new());
16//!
17//!     let server = SmtpServer::new(config, registry)?;
18//!     server.start().await?;
19//!
20//!     Ok(())
21//! }
22//! ```
23
24mod fixtures;
25/// Unified protocol server lifecycle implementation
26pub mod protocol_server;
27mod server;
28mod spec_registry;
29
30pub use fixtures::*;
31pub use server::*;
32pub use spec_registry::*;
33
34use serde::{Deserialize, Serialize};
35use std::path::PathBuf;
36
37/// SMTP server configuration
38#[derive(Debug, Clone, Serialize, Deserialize)]
39pub struct SmtpConfig {
40    /// Server port (default: 1025)
41    pub port: u16,
42    /// Host address (default: 0.0.0.0)
43    pub host: String,
44    /// Server hostname for SMTP greeting
45    pub hostname: String,
46    /// Directory containing fixture files
47    pub fixtures_dir: Option<PathBuf>,
48    /// Connection timeout in seconds
49    pub timeout_secs: u64,
50    /// Maximum connections
51    pub max_connections: usize,
52    /// Enable mailbox storage
53    pub enable_mailbox: bool,
54    /// Maximum mailbox size
55    pub max_mailbox_messages: usize,
56    /// Enable STARTTLS support
57    pub enable_starttls: bool,
58    /// Path to TLS certificate file
59    pub tls_cert_path: Option<PathBuf>,
60    /// Path to TLS private key file
61    pub tls_key_path: Option<PathBuf>,
62}
63
64impl Default for SmtpConfig {
65    fn default() -> Self {
66        Self {
67            port: 1025,
68            host: "0.0.0.0".to_string(),
69            hostname: "mockforge-smtp".to_string(),
70            fixtures_dir: Some(PathBuf::from("./fixtures/smtp")),
71            timeout_secs: 300,
72            max_connections: 10,
73            enable_mailbox: true,
74            max_mailbox_messages: 1000,
75            enable_starttls: false,
76            tls_cert_path: None,
77            tls_key_path: None,
78        }
79    }
80}
81
82#[cfg(test)]
83mod tests {
84    use super::*;
85    use mockforge_core::protocol_abstraction::Protocol;
86
87    #[test]
88    fn test_default_config() {
89        let config = SmtpConfig::default();
90        assert_eq!(config.port, 1025);
91        assert_eq!(config.host, "0.0.0.0");
92        assert_eq!(config.hostname, "mockforge-smtp");
93    }
94
95    #[test]
96    fn test_protocol_display() {
97        assert_eq!(Protocol::Smtp.to_string(), "SMTP");
98    }
99
100    #[test]
101    fn test_smtp_config_all_defaults() {
102        let config = SmtpConfig::default();
103        assert_eq!(config.timeout_secs, 300);
104        assert_eq!(config.max_connections, 10);
105        assert!(config.enable_mailbox);
106        assert_eq!(config.max_mailbox_messages, 1000);
107        assert!(!config.enable_starttls);
108        assert!(config.tls_cert_path.is_none());
109        assert!(config.tls_key_path.is_none());
110        assert_eq!(config.fixtures_dir, Some(PathBuf::from("./fixtures/smtp")));
111    }
112
113    #[test]
114    fn test_smtp_config_serialize() {
115        let config = SmtpConfig::default();
116        let json = serde_json::to_string(&config).unwrap();
117        assert!(json.contains("\"port\":1025"));
118        assert!(json.contains("mockforge-smtp"));
119    }
120
121    #[test]
122    fn test_smtp_config_deserialize() {
123        let json = r#"{
124            "port": 2025,
125            "host": "127.0.0.1",
126            "hostname": "test-smtp",
127            "timeout_secs": 600,
128            "max_connections": 20,
129            "enable_mailbox": false,
130            "max_mailbox_messages": 500,
131            "enable_starttls": true,
132            "fixtures_dir": "/tmp/fixtures"
133        }"#;
134        let config: SmtpConfig = serde_json::from_str(json).unwrap();
135        assert_eq!(config.port, 2025);
136        assert_eq!(config.host, "127.0.0.1");
137        assert_eq!(config.hostname, "test-smtp");
138        assert_eq!(config.timeout_secs, 600);
139        assert_eq!(config.max_connections, 20);
140        assert!(!config.enable_mailbox);
141        assert!(config.enable_starttls);
142    }
143
144    #[test]
145    fn test_smtp_config_clone() {
146        let config = SmtpConfig::default();
147        let cloned = config.clone();
148        assert_eq!(config.port, cloned.port);
149        assert_eq!(config.hostname, cloned.hostname);
150    }
151
152    #[test]
153    fn test_smtp_config_debug() {
154        let config = SmtpConfig::default();
155        let debug = format!("{:?}", config);
156        assert!(debug.contains("SmtpConfig"));
157        assert!(debug.contains("1025"));
158    }
159
160    #[test]
161    fn test_smtp_config_with_tls() {
162        let config = SmtpConfig {
163            enable_starttls: true,
164            tls_cert_path: Some(PathBuf::from("/path/to/cert.pem")),
165            tls_key_path: Some(PathBuf::from("/path/to/key.pem")),
166            ..SmtpConfig::default()
167        };
168        assert!(config.enable_starttls);
169        assert!(config.tls_cert_path.is_some());
170        assert!(config.tls_key_path.is_some());
171    }
172
173    #[test]
174    fn test_smtp_config_custom_fixtures_dir() {
175        let config = SmtpConfig {
176            fixtures_dir: Some(PathBuf::from("/custom/fixtures")),
177            ..SmtpConfig::default()
178        };
179        assert_eq!(config.fixtures_dir, Some(PathBuf::from("/custom/fixtures")));
180    }
181}