pg_embedded_setup_unpriv/
error.rs1use color_eyre::Report;
4use thiserror::Error;
5
6pub type Result<T> = std::result::Result<T, PgEmbeddedError>;
8
9pub type BootstrapResult<T> = std::result::Result<T, BootstrapError>;
11
12pub type PrivilegeResult<T> = std::result::Result<T, PrivilegeError>;
14
15pub type ConfigResult<T> = std::result::Result<T, ConfigError>;
17
18#[derive(Debug, Error)]
20pub enum PgEmbeddedError {
21 #[error("bootstrap failed: {0}")]
23 Bootstrap(#[from] BootstrapError),
24 #[error("privilege management failed: {0}")]
26 Privilege(#[from] PrivilegeError),
27 #[error("configuration parsing failed: {0}")]
29 Config(#[from] ConfigError),
30}
31
32#[derive(Debug, Clone, Copy, Default, Eq, PartialEq)]
34pub enum BootstrapErrorKind {
35 #[default]
37 Other,
38 WorkerBinaryMissing,
40 WorkerBinaryPathNonUtf8,
42}
43
44#[derive(Debug, Error)]
46#[error("{report}")]
47pub struct BootstrapError {
48 kind: BootstrapErrorKind,
49 #[source]
50 report: Report,
51}
52
53impl BootstrapError {
54 #[must_use]
57 pub const fn new(kind: BootstrapErrorKind, report: Report) -> Self {
58 Self { kind, report }
59 }
60
61 #[must_use]
63 pub const fn kind(&self) -> BootstrapErrorKind {
64 self.kind
65 }
66
67 pub fn into_report(self) -> Report {
69 self.report
70 }
71}
72
73impl From<Report> for BootstrapError {
74 fn from(report: Report) -> Self {
75 Self::new(BootstrapErrorKind::Other, report)
76 }
77}
78
79impl From<PrivilegeError> for BootstrapError {
80 fn from(err: PrivilegeError) -> Self {
81 let PrivilegeError(report) = err;
82 Self::new(BootstrapErrorKind::Other, report)
83 }
84}
85
86impl From<ConfigError> for BootstrapError {
87 fn from(err: ConfigError) -> Self {
88 let ConfigError(report) = err;
89 Self::new(BootstrapErrorKind::Other, report)
90 }
91}
92
93impl From<PgEmbeddedError> for BootstrapError {
94 fn from(err: PgEmbeddedError) -> Self {
95 match err {
96 PgEmbeddedError::Bootstrap(inner) => inner,
97 PgEmbeddedError::Privilege(inner) => inner.into(),
98 PgEmbeddedError::Config(inner) => inner.into(),
99 }
100 }
101}
102
103#[derive(Debug, Error)]
105#[error(transparent)]
106pub struct PrivilegeError(#[from] Report);
107
108#[derive(Debug, Error)]
110#[error(transparent)]
111pub struct ConfigError(#[from] Report);
112
113#[cfg(test)]
114mod tests {
115 use super::*;
118 use color_eyre::eyre::eyre;
119 use rstest::rstest;
120
121 #[rstest]
122 #[case::bootstrap(
123 "PG_EMBEDDED_WORKER must be set",
124 "bootstrap failed:",
125 |msg: &str| PgEmbeddedError::Bootstrap(BootstrapError::from(eyre!("{}", msg)))
126 )]
127 #[case::privilege(
128 "failed to drop privileges",
129 "privilege management failed:",
130 |msg: &str| PgEmbeddedError::Privilege(PrivilegeError::from(eyre!("{}", msg)))
131 )]
132 #[case::config(
133 "invalid port number",
134 "configuration parsing failed:",
135 |msg: &str| PgEmbeddedError::Config(ConfigError::from(eyre!("{}", msg)))
136 )]
137 fn pg_embedded_error_includes_inner_message(
138 #[case] inner_message: &str,
139 #[case] expected_prefix: &str,
140 #[case] constructor: fn(&str) -> PgEmbeddedError,
141 ) {
142 let pg_err = constructor(inner_message);
143
144 let display = pg_err.to_string();
145
146 assert!(
147 display.contains(expected_prefix),
148 "expected '{expected_prefix}' prefix, got: {display}"
149 );
150 assert!(
151 display.contains(inner_message),
152 "expected inner message '{inner_message}' in display, got: {display}"
153 );
154 }
155
156 #[test]
157 fn bootstrap_error_displays_report_message() {
158 let inner_message = "database connection failed";
159 let err = BootstrapError::from(eyre!(inner_message));
160
161 let display = err.to_string();
162
163 assert!(
164 display.contains(inner_message),
165 "expected '{inner_message}' in display, got: {display}"
166 );
167 }
168}