postgresql_archive/
error.rs

1/// PostgreSQL archive result type
2pub type Result<T, E = Error> = core::result::Result<T, E>;
3
4/// PostgreSQL archive errors
5#[derive(Debug, thiserror::Error)]
6pub enum Error {
7    /// Asset not found
8    #[error("asset not found")]
9    AssetNotFound,
10    /// Asset hash not found
11    #[error("asset hash not found for asset '{0}'")]
12    AssetHashNotFound(String),
13    /// Error when the hash of the archive does not match the expected hash
14    #[error("Archive hash [{archive_hash}] does not match expected hash [{hash}]")]
15    ArchiveHashMismatch { archive_hash: String, hash: String },
16    /// Invalid version
17    #[error("version '{0}' is invalid")]
18    InvalidVersion(String),
19    /// IO error
20    #[error("{0}")]
21    IoError(String),
22    /// Parse error
23    #[error("{0}")]
24    ParseError(String),
25    /// Poisoned lock
26    #[error("poisoned lock '{0}'")]
27    PoisonedLock(String),
28    /// Repository failure
29    #[error("{0}")]
30    RepositoryFailure(String),
31    /// Unexpected error
32    #[error("{0}")]
33    Unexpected(String),
34    /// Unsupported extractor
35    #[error("unsupported extractor for '{0}'")]
36    UnsupportedExtractor(String),
37    /// Unsupported hasher
38    #[error("unsupported hasher for '{0}'")]
39    UnsupportedHasher(String),
40    /// Unsupported hasher
41    #[error("unsupported matcher for '{0}'")]
42    UnsupportedMatcher(String),
43    /// Unsupported repository
44    #[error("unsupported repository for '{0}'")]
45    UnsupportedRepository(String),
46    /// Version not found
47    #[error("version not found for '{0}'")]
48    VersionNotFound(String),
49}
50
51/// Converts a [`regex_lite::Error`] into an [`ParseError`](Error::ParseError)
52impl From<regex_lite::Error> for Error {
53    fn from(error: regex_lite::Error) -> Self {
54        Error::ParseError(error.to_string())
55    }
56}
57
58/// Converts a [`reqwest::Error`] into an [`IoError`](Error::IoError)
59impl From<reqwest::Error> for Error {
60    fn from(error: reqwest::Error) -> Self {
61        Error::IoError(error.to_string())
62    }
63}
64
65/// Converts a [`reqwest_middleware::Error`] into an [`IoError`](Error::IoError)
66impl From<reqwest_middleware::Error> for Error {
67    fn from(error: reqwest_middleware::Error) -> Self {
68        Error::IoError(error.to_string())
69    }
70}
71
72/// Converts a [`std::io::Error`] into an [`IoError`](Error::IoError)
73impl From<std::io::Error> for Error {
74    fn from(error: std::io::Error) -> Self {
75        Error::IoError(error.to_string())
76    }
77}
78
79/// Converts a [`std::time::SystemTimeError`] into an [`IoError`](Error::IoError)
80impl From<std::time::SystemTimeError> for Error {
81    fn from(error: std::time::SystemTimeError) -> Self {
82        Error::IoError(error.to_string())
83    }
84}
85
86/// Converts a [`std::num::ParseIntError`] into an [`ParseError`](Error::ParseError)
87impl From<std::num::ParseIntError> for Error {
88    fn from(error: std::num::ParseIntError) -> Self {
89        Error::ParseError(error.to_string())
90    }
91}
92
93/// Converts a [`semver::Error`] into an [`ParseError`](Error::ParseError)
94impl From<semver::Error> for Error {
95    fn from(error: semver::Error) -> Self {
96        Error::IoError(error.to_string())
97    }
98}
99
100/// Converts a [`std::path::StripPrefixError`] into an [`ParseError`](Error::ParseError)
101impl From<std::path::StripPrefixError> for Error {
102    fn from(error: std::path::StripPrefixError) -> Self {
103        Error::ParseError(error.to_string())
104    }
105}
106
107/// Converts a [`url::ParseError`] into an [`ParseError`](Error::ParseError)
108impl From<url::ParseError> for Error {
109    fn from(error: url::ParseError) -> Self {
110        Error::ParseError(error.to_string())
111    }
112}
113
114/// These are relatively low value tests; they are here to reduce the coverage gap and
115/// ensure that the error conversions are working as expected.
116#[cfg(test)]
117mod test {
118    use super::*;
119    use anyhow::anyhow;
120    use semver::VersionReq;
121    use std::ops::Add;
122    use std::path::PathBuf;
123    use std::str::FromStr;
124    use std::time::{Duration, SystemTime};
125
126    #[test]
127    fn test_from_regex_error() {
128        let regex_error = regex_lite::Regex::new("(?=a)").expect_err("regex error");
129        let error = Error::from(regex_error);
130        assert_eq!(error.to_string(), "look-around is not supported");
131    }
132
133    #[tokio::test]
134    async fn test_from_reqwest_error() {
135        let result = reqwest::get("https://a.com").await;
136        assert!(result.is_err());
137        if let Err(error) = result {
138            let error = Error::from(error);
139            assert!(error.to_string().contains("error sending request"));
140        }
141    }
142
143    #[tokio::test]
144    async fn test_from_reqwest_middeleware_error() {
145        let reqwest_middleware_error =
146            reqwest_middleware::Error::Middleware(anyhow!("middleware error: test"));
147        let error = Error::from(reqwest_middleware_error);
148        assert!(error.to_string().contains("middleware error: test"));
149    }
150
151    #[test]
152    fn test_from_io_error() {
153        let io_error = std::io::Error::new(std::io::ErrorKind::NotFound, "test");
154        let error = Error::from(io_error);
155        assert_eq!(error.to_string(), "test");
156    }
157
158    #[test]
159    fn test_from_parse_int_error() {
160        let parse_int_error = u64::from_str("test").expect_err("parse int error");
161        let error = Error::from(parse_int_error);
162        assert_eq!(error.to_string(), "invalid digit found in string");
163    }
164
165    #[test]
166    fn test_from_semver_error() {
167        let semver_error = VersionReq::parse("foo").expect_err("semver error");
168        let error = Error::from(semver_error);
169        assert_eq!(
170            error.to_string(),
171            "unexpected character 'f' while parsing major version number"
172        );
173    }
174
175    #[test]
176    fn test_from_strip_prefix_error() {
177        let path = PathBuf::from("test");
178        let strip_prefix_error = path.strip_prefix("foo").expect_err("strip prefix error");
179        let error = Error::from(strip_prefix_error);
180        assert_eq!(error.to_string(), "prefix not found");
181    }
182
183    #[test]
184    fn test_from_system_time_error() {
185        let future_time = SystemTime::now().add(Duration::from_secs(300));
186        let system_time_error = SystemTime::now()
187            .duration_since(future_time)
188            .expect_err("system time error");
189        let error = Error::from(system_time_error);
190        assert_eq!(
191            error.to_string(),
192            "second time provided was later than self"
193        );
194    }
195
196    #[test]
197    fn test_from_url_parse_error() {
198        let parse_error = url::ParseError::EmptyHost;
199        let error = Error::from(parse_error);
200        assert_eq!(error.to_string(), "empty host");
201    }
202}