1use thiserror::Error;
4
5pub type Result<T> = std::result::Result<T, Error>;
7
8#[derive(Error, Debug)]
10pub enum Error {
11 #[error("Mock server is already running on port {0}. Call stop() before starting again.")]
13 ServerAlreadyStarted(u16),
14
15 #[error("Mock server has not been started yet. Call start() first.")]
17 ServerNotStarted,
18
19 #[error("Port {0} is already in use. Try using a different port or enable auto_port().")]
21 PortInUse(u16),
22
23 #[error("Port discovery failed: {0}\nTip: Try expanding the port range using port_range(start, end).")]
25 PortDiscoveryFailed(String),
26
27 #[error("Invalid configuration: {0}\nCheck your configuration file or builder settings.")]
29 InvalidConfig(String),
30
31 #[error("Invalid stub: {0}\nEnsure method, path, and response body are properly set.")]
33 InvalidStub(String),
34
35 #[error("Stub not found for {method} {path}. Available stubs: {available}")]
37 StubNotFound {
38 method: String,
40 path: String,
42 available: String,
44 },
45
46 #[error("HTTP error: {0}\nThis may indicate a network or protocol issue.")]
48 Http(#[from] axum::http::Error),
49
50 #[error("IO error: {0}\nCheck file permissions and network connectivity.")]
52 Io(#[from] std::io::Error),
53
54 #[error("JSON serialization error: {0}\nEnsure your request/response body is valid JSON.")]
56 Json(#[from] serde_json::Error),
57
58 #[error("MockForge core error: {0}")]
60 Core(#[from] mockforge_core::Error),
61
62 #[error("Server failed to start within {timeout_secs} seconds.\nCheck logs for details or increase timeout.")]
64 StartupTimeout {
65 timeout_secs: u64,
67 },
68
69 #[error("Server failed to stop within {timeout_secs} seconds.\nSome connections may still be active.")]
71 ShutdownTimeout {
72 timeout_secs: u64,
74 },
75
76 #[error("Admin API error ({operation}): {message}\nEndpoint: {endpoint}")]
78 AdminApiError {
79 operation: String,
81 message: String,
83 endpoint: String,
85 },
86
87 #[error("{0}")]
89 General(String),
90}
91
92impl Error {
93 pub fn admin_api_error(
107 operation: impl Into<String>,
108 message: impl Into<String>,
109 endpoint: impl Into<String>,
110 ) -> Self {
111 Error::AdminApiError {
112 operation: operation.into(),
113 message: message.into(),
114 endpoint: endpoint.into(),
115 }
116 }
117
118 pub fn stub_not_found(
132 method: impl Into<String>,
133 path: impl Into<String>,
134 available: Vec<String>,
135 ) -> Self {
136 Error::StubNotFound {
137 method: method.into(),
138 path: path.into(),
139 available: if available.is_empty() {
140 "none".to_string()
141 } else {
142 available.join(", ")
143 },
144 }
145 }
146
147 pub fn to_log_string(&self) -> String {
161 format!("{}", self).replace('\n', " | ")
162 }
163}