eggserve_core/server/
errors.rs1use std::fmt;
17
18#[derive(Debug)]
20pub enum ServerError {
21 Bind(std::io::Error),
23 Config(String),
25 AlreadyStarted,
27 NotStarted,
29 Accept(std::io::Error),
31 TlsSetup(String),
33 Transport(String),
35 ShutdownTimeout,
37 Startup(String),
39 Terminal(String),
41}
42
43impl fmt::Display for ServerError {
44 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
45 match self {
46 Self::Bind(e) => write!(f, "failed to bind: {}", e),
47 Self::Config(msg) => write!(f, "configuration error: {}", msg),
48 Self::AlreadyStarted => write!(f, "server already started"),
49 Self::NotStarted => write!(f, "server not started"),
50 Self::Accept(e) => write!(f, "accept error: {}", e),
51 Self::TlsSetup(msg) => write!(f, "TLS setup error: {}", msg),
52 Self::Transport(msg) => write!(f, "transport error: {}", msg),
53 Self::ShutdownTimeout => write!(f, "graceful shutdown timed out"),
54 Self::Startup(msg) => write!(f, "startup error: {}", msg),
55 Self::Terminal(msg) => write!(f, "terminal runtime error: {}", msg),
56 }
57 }
58}
59
60impl std::error::Error for ServerError {
61 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
62 match self {
63 Self::Bind(e) => Some(e),
64 Self::Accept(e) => Some(e),
65 _ => None,
66 }
67 }
68}
69
70impl From<std::io::Error> for ServerError {
71 fn from(e: std::io::Error) -> Self {
72 ServerError::Bind(e)
73 }
74}
75
76#[derive(Debug, Clone, Copy, PartialEq, Eq)]
78pub enum ShutdownResult {
79 Clean,
81 Timeout,
83 Forced,
85}
86
87impl fmt::Display for ShutdownResult {
88 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
89 match self {
90 Self::Clean => write!(f, "clean shutdown"),
91 Self::Timeout => write!(f, "shutdown timed out"),
92 Self::Forced => write!(f, "forced shutdown"),
93 }
94 }
95}
96
97#[cfg(test)]
98mod tests {
99 use super::*;
100
101 #[test]
102 fn server_error_display() {
103 let err = ServerError::Config("bad value".into());
104 assert!(err.to_string().contains("bad value"));
105
106 let err = ServerError::AlreadyStarted;
107 assert!(err.to_string().contains("already started"));
108
109 let err = ServerError::NotStarted;
110 assert!(err.to_string().contains("not started"));
111
112 let err = ServerError::TlsSetup("invalid cert".into());
113 assert!(err.to_string().contains("TLS setup error"));
114 assert!(err.to_string().contains("invalid cert"));
115
116 let err = ServerError::Transport("body conversion failed".into());
117 assert!(err.to_string().contains("transport error"));
118 assert!(err.to_string().contains("body conversion failed"));
119
120 let err = ServerError::ShutdownTimeout;
121 assert!(err.to_string().contains("timed out"));
122
123 let err = ServerError::Startup("bind failed".into());
124 assert!(err.to_string().contains("startup error"));
125 assert!(err.to_string().contains("bind failed"));
126
127 let err = ServerError::Terminal("runtime crashed".into());
128 assert!(err.to_string().contains("terminal runtime error"));
129 assert!(err.to_string().contains("runtime crashed"));
130 }
131
132 #[test]
133 fn server_error_is_error() {
134 let err: Box<dyn std::error::Error> = Box::new(ServerError::Config("test".into()));
135 assert!(!err.to_string().is_empty());
136 }
137
138 #[test]
139 fn shutdown_result_display() {
140 assert_eq!(ShutdownResult::Clean.to_string(), "clean shutdown");
141 assert_eq!(ShutdownResult::Timeout.to_string(), "shutdown timed out");
142 assert_eq!(ShutdownResult::Forced.to_string(), "forced shutdown");
143 }
144
145 #[test]
146 fn shutdown_result_equality() {
147 assert_eq!(ShutdownResult::Clean, ShutdownResult::Clean);
148 assert_ne!(ShutdownResult::Clean, ShutdownResult::Timeout);
149 assert_ne!(ShutdownResult::Forced, ShutdownResult::Clean);
150 }
151}