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}
41
42#[derive(Debug, Error)]
44#[error("{report}")]
45pub struct BootstrapError {
46 kind: BootstrapErrorKind,
47 #[source]
48 report: Report,
49}
50
51impl BootstrapError {
52 #[must_use]
55 pub const fn new(kind: BootstrapErrorKind, report: Report) -> Self {
56 Self { kind, report }
57 }
58
59 #[must_use]
61 pub const fn kind(&self) -> BootstrapErrorKind {
62 self.kind
63 }
64
65 pub fn into_report(self) -> Report {
67 self.report
68 }
69}
70
71impl From<Report> for BootstrapError {
72 fn from(report: Report) -> Self {
73 Self::new(BootstrapErrorKind::Other, report)
74 }
75}
76
77impl From<PrivilegeError> for BootstrapError {
78 fn from(err: PrivilegeError) -> Self {
79 let PrivilegeError(report) = err;
80 Self::new(BootstrapErrorKind::Other, report)
81 }
82}
83
84impl From<ConfigError> for BootstrapError {
85 fn from(err: ConfigError) -> Self {
86 let ConfigError(report) = err;
87 Self::new(BootstrapErrorKind::Other, report)
88 }
89}
90
91impl From<PgEmbeddedError> for BootstrapError {
92 fn from(err: PgEmbeddedError) -> Self {
93 match err {
94 PgEmbeddedError::Bootstrap(inner) => inner,
95 PgEmbeddedError::Privilege(inner) => inner.into(),
96 PgEmbeddedError::Config(inner) => inner.into(),
97 }
98 }
99}
100
101#[derive(Debug, Error)]
103#[error(transparent)]
104pub struct PrivilegeError(#[from] Report);
105
106#[derive(Debug, Error)]
108#[error(transparent)]
109pub struct ConfigError(#[from] Report);
110
111#[cfg(test)]
112mod tests {
113 use super::*;
116 use color_eyre::eyre::eyre;
117 use rstest::rstest;
118
119 #[rstest]
120 #[case::bootstrap(
121 "PG_EMBEDDED_WORKER must be set",
122 "bootstrap failed:",
123 |msg: &str| PgEmbeddedError::Bootstrap(BootstrapError::from(eyre!("{}", msg)))
124 )]
125 #[case::privilege(
126 "failed to drop privileges",
127 "privilege management failed:",
128 |msg: &str| PgEmbeddedError::Privilege(PrivilegeError::from(eyre!("{}", msg)))
129 )]
130 #[case::config(
131 "invalid port number",
132 "configuration parsing failed:",
133 |msg: &str| PgEmbeddedError::Config(ConfigError::from(eyre!("{}", msg)))
134 )]
135 fn pg_embedded_error_includes_inner_message(
136 #[case] inner_message: &str,
137 #[case] expected_prefix: &str,
138 #[case] constructor: fn(&str) -> PgEmbeddedError,
139 ) {
140 let pg_err = constructor(inner_message);
141
142 let display = pg_err.to_string();
143
144 assert!(
145 display.contains(expected_prefix),
146 "expected '{expected_prefix}' prefix, got: {display}"
147 );
148 assert!(
149 display.contains(inner_message),
150 "expected inner message '{inner_message}' in display, got: {display}"
151 );
152 }
153
154 #[test]
155 fn bootstrap_error_displays_report_message() {
156 let inner_message = "database connection failed";
157 let err = BootstrapError::from(eyre!(inner_message));
158
159 let display = err.to_string();
160
161 assert!(
162 display.contains(inner_message),
163 "expected '{inner_message}' in display, got: {display}"
164 );
165 }
166}