use thiserror::Error;
#[non_exhaustive]
#[derive(Error, Debug, PartialEq, Eq)]
pub enum ConfigError {
#[error("Config error: the introspection URL is not valid")]
InvalidIntrospectionURL,
#[error("Config error: invalid authorization value")]
InvalidAuthorizationValue,
#[error("Config error: invalid consumer_by value")]
InvalidConsumerBy,
}
#[non_exhaustive]
#[derive(Error, Debug, PartialEq, Eq)]
pub enum ValidationError {
#[error("Token has expired.")]
TokenExpired,
#[error("Token has been revoked.")]
TokenRevoked,
#[error("The required scopes are not authorized")]
InvalidScopes,
#[error("Token is inactive.")]
TokenInactive,
#[error("The contract collector is not set")]
EmptyContractValidator,
#[error("Invalid Client")]
InvalidClientContracts {
name: Option<String>,
id: Option<String>,
},
}
#[non_exhaustive]
#[derive(Error, Debug)]
pub enum IntrospectionError {
#[error("Introspection request failed: {0}")]
RequestFailed(String),
#[error("Introspection HTTP error: status={status}, body={body}")]
HttpError { status: u32, body: String },
#[error("Failed to parse introspection response: {0}")]
ParseError(String),
#[error("Token validation failed: {0}")]
Validation(#[from] ValidationError),
}
#[derive(Error, Debug, PartialEq, Eq)]
pub(crate) enum TokenError {
#[error("Unexpected error when deserializing cached value: {msg:}")]
BinaryDeserializeError { msg: String },
#[error("Unexpected error when serializing cached value: {msg:}")]
BinarySerializeError { msg: String },
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn config_error_messages_contain_context() {
let err = ConfigError::InvalidIntrospectionURL;
assert!(err.to_string().contains("introspection URL"));
assert!(!err.to_string().contains("authorization"));
let err = ConfigError::InvalidAuthorizationValue;
assert!(err.to_string().contains("authorization"));
assert!(!err.to_string().contains("introspection URL")); }
#[test]
fn validation_errors_are_distinct() {
let expired = ValidationError::TokenExpired.to_string();
let revoked = ValidationError::TokenRevoked.to_string();
let scopes = ValidationError::InvalidScopes.to_string();
assert!(expired.contains("expired"));
assert!(revoked.contains("revoked"));
assert!(scopes.contains("scopes"));
assert_ne!(expired, revoked);
assert_ne!(revoked, scopes);
}
#[test]
fn token_error_messages_include_dynamic_fields() {
let err1 = TokenError::BinaryDeserializeError {
msg: "invalid data".to_string(),
};
let err2 = TokenError::BinaryDeserializeError {
msg: "other error".to_string(),
};
assert!(err1.to_string().contains("invalid data"));
assert!(err2.to_string().contains("other error"));
assert_ne!(err1.to_string(), err2.to_string());
let err3 = TokenError::BinarySerializeError {
msg: "serialize error".to_string(),
};
assert!(err3.to_string().contains("serialize error"));
assert_ne!(err1.to_string(), err3.to_string()); }
}