Skip to main content

macp_core/
error.rs

1use thiserror::Error;
2
3#[derive(Debug, Error)]
4pub enum MacpError {
5    #[error("InvalidMacpVersion")]
6    InvalidMacpVersion,
7    #[error("InvalidEnvelope")]
8    InvalidEnvelope,
9    #[error("SessionAlreadyExists")]
10    SessionAlreadyExists,
11    #[error("UnknownSession")]
12    UnknownSession,
13    #[error("SessionNotOpen")]
14    SessionNotOpen,
15    #[error("TtlExpired")]
16    TtlExpired,
17    #[error("InvalidTtl")]
18    InvalidTtl,
19    #[error("UnknownMode")]
20    UnknownMode,
21    #[error("InvalidModeState")]
22    InvalidModeState,
23    #[error("InvalidPayload")]
24    InvalidPayload,
25    #[error("Forbidden")]
26    Forbidden,
27    #[error("Unauthenticated")]
28    Unauthenticated,
29    /// Kept for RFC error-code completeness.  The runtime currently represents
30    /// duplicate detection via `ProcessResult { duplicate: true }` at the Ack
31    /// level rather than returning this as an error.
32    #[error("DuplicateMessage")]
33    DuplicateMessage,
34    #[error("PayloadTooLarge")]
35    PayloadTooLarge,
36    #[error("RateLimited")]
37    RateLimited,
38    #[error("StorageFailed")]
39    StorageFailed,
40    #[error("InvalidSessionId")]
41    InvalidSessionId,
42    #[error("UnknownPolicyVersion")]
43    UnknownPolicyVersion,
44    #[error("PolicyDenied")]
45    PolicyDenied { reasons: Vec<String> },
46    #[error("InvalidPolicyDefinition")]
47    InvalidPolicyDefinition,
48}
49
50impl MacpError {
51    /// Returns the RFC error code string for this error variant.
52    pub fn error_code(&self) -> &'static str {
53        match self {
54            MacpError::InvalidMacpVersion => "UNSUPPORTED_PROTOCOL_VERSION",
55            MacpError::InvalidEnvelope => "INVALID_ENVELOPE",
56            MacpError::SessionAlreadyExists => "SESSION_ALREADY_EXISTS",
57            MacpError::UnknownSession => "SESSION_NOT_FOUND",
58            MacpError::SessionNotOpen => "SESSION_NOT_OPEN",
59            MacpError::TtlExpired => "SESSION_NOT_OPEN",
60            MacpError::InvalidTtl => "INVALID_ENVELOPE",
61            MacpError::UnknownMode => "MODE_NOT_SUPPORTED",
62            MacpError::InvalidModeState => "INVALID_ENVELOPE",
63            MacpError::InvalidPayload => "INVALID_ENVELOPE",
64            MacpError::Forbidden => "FORBIDDEN",
65            MacpError::Unauthenticated => "UNAUTHENTICATED",
66            MacpError::DuplicateMessage => "DUPLICATE_MESSAGE",
67            MacpError::PayloadTooLarge => "PAYLOAD_TOO_LARGE",
68            MacpError::RateLimited => "RATE_LIMITED",
69            MacpError::StorageFailed => "INTERNAL_ERROR",
70            MacpError::InvalidSessionId => "INVALID_SESSION_ID",
71            MacpError::UnknownPolicyVersion => "UNKNOWN_POLICY_VERSION",
72            MacpError::PolicyDenied { .. } => "POLICY_DENIED",
73            MacpError::InvalidPolicyDefinition => "INVALID_POLICY_DEFINITION",
74        }
75    }
76}
77
78#[cfg(test)]
79mod tests {
80    use super::*;
81
82    #[test]
83    fn error_code_mapping_covers_all_variants() {
84        let cases: Vec<(MacpError, &str)> = vec![
85            (
86                MacpError::InvalidMacpVersion,
87                "UNSUPPORTED_PROTOCOL_VERSION",
88            ),
89            (MacpError::InvalidEnvelope, "INVALID_ENVELOPE"),
90            (MacpError::SessionAlreadyExists, "SESSION_ALREADY_EXISTS"),
91            (MacpError::UnknownSession, "SESSION_NOT_FOUND"),
92            (MacpError::SessionNotOpen, "SESSION_NOT_OPEN"),
93            (MacpError::TtlExpired, "SESSION_NOT_OPEN"),
94            (MacpError::InvalidTtl, "INVALID_ENVELOPE"),
95            (MacpError::UnknownMode, "MODE_NOT_SUPPORTED"),
96            (MacpError::InvalidModeState, "INVALID_ENVELOPE"),
97            (MacpError::InvalidPayload, "INVALID_ENVELOPE"),
98            (MacpError::Forbidden, "FORBIDDEN"),
99            (MacpError::Unauthenticated, "UNAUTHENTICATED"),
100            (MacpError::DuplicateMessage, "DUPLICATE_MESSAGE"),
101            (MacpError::PayloadTooLarge, "PAYLOAD_TOO_LARGE"),
102            (MacpError::RateLimited, "RATE_LIMITED"),
103            (MacpError::StorageFailed, "INTERNAL_ERROR"),
104            (MacpError::InvalidSessionId, "INVALID_SESSION_ID"),
105            (MacpError::UnknownPolicyVersion, "UNKNOWN_POLICY_VERSION"),
106            (
107                MacpError::PolicyDenied {
108                    reasons: vec!["test".into()],
109                },
110                "POLICY_DENIED",
111            ),
112            (
113                MacpError::InvalidPolicyDefinition,
114                "INVALID_POLICY_DEFINITION",
115            ),
116        ];
117
118        for (error, expected_code) in cases {
119            assert_eq!(
120                error.error_code(),
121                expected_code,
122                "error_code() mismatch for {:?}",
123                error
124            );
125            assert!(!error.to_string().is_empty());
126        }
127    }
128
129    #[test]
130    fn display_matches_variant_name() {
131        assert_eq!(
132            MacpError::InvalidMacpVersion.to_string(),
133            "InvalidMacpVersion"
134        );
135        assert_eq!(MacpError::Forbidden.to_string(), "Forbidden");
136        assert_eq!(MacpError::TtlExpired.to_string(), "TtlExpired");
137        assert_eq!(MacpError::Unauthenticated.to_string(), "Unauthenticated");
138        assert_eq!(MacpError::DuplicateMessage.to_string(), "DuplicateMessage");
139        assert_eq!(MacpError::PayloadTooLarge.to_string(), "PayloadTooLarge");
140        assert_eq!(MacpError::RateLimited.to_string(), "RateLimited");
141        assert_eq!(MacpError::StorageFailed.to_string(), "StorageFailed");
142        assert_eq!(MacpError::InvalidSessionId.to_string(), "InvalidSessionId");
143        assert_eq!(
144            MacpError::UnknownPolicyVersion.to_string(),
145            "UnknownPolicyVersion"
146        );
147        assert_eq!(
148            MacpError::PolicyDenied {
149                reasons: vec!["test".into()]
150            }
151            .to_string(),
152            "PolicyDenied"
153        );
154    }
155}