use nexo_auth::Channel;
use thiserror::Error;
#[derive(Debug, Error)]
pub enum PollerError {
#[error("config invalid for job '{job}': {reason}")]
Config { job: String, reason: String },
#[error("credentials missing: agent '{agent}' has no '{channel}' bound")]
CredentialsMissing { agent: String, channel: Channel },
#[error("transient: {0}")]
Transient(#[source] anyhow::Error),
#[error("permanent: {0}")]
Permanent(#[source] anyhow::Error),
#[error(transparent)]
Other(#[from] anyhow::Error),
}
impl PollerError {
pub fn classify(&self) -> ErrorClass {
match self {
Self::Config { .. } => ErrorClass::Config,
Self::CredentialsMissing { .. } => ErrorClass::Permanent,
Self::Transient(_) => ErrorClass::Transient,
Self::Permanent(_) => ErrorClass::Permanent,
Self::Other(_) => ErrorClass::Transient,
}
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum ErrorClass {
Config,
Transient,
Permanent,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn classify_dispatch() {
let e = PollerError::Transient(anyhow::anyhow!("503"));
assert_eq!(e.classify(), ErrorClass::Transient);
let e = PollerError::Permanent(anyhow::anyhow!("revoked"));
assert_eq!(e.classify(), ErrorClass::Permanent);
let e = PollerError::Config {
job: "x".into(),
reason: "missing field".into(),
};
assert_eq!(e.classify(), ErrorClass::Config);
let e = PollerError::CredentialsMissing {
agent: "ana".into(),
channel: nexo_auth::handle::GOOGLE,
};
assert_eq!(e.classify(), ErrorClass::Permanent);
}
#[test]
fn other_wraps_anyhow_as_transient() {
let inner: anyhow::Error = anyhow::anyhow!("network glitch");
let e: PollerError = inner.into();
assert_eq!(e.classify(), ErrorClass::Transient);
}
}