Skip to main content

akash_deploy_rs/
error.rs

1//! Error types for Akash deployment workflow.
2//!
3//! No `anyhow` leakage. Explicit, typed errors.
4
5#[derive(Debug, thiserror::Error)]
6pub enum DeployError {
7    #[error("chain query failed: {0}")]
8    Query(String),
9
10    #[error("transaction failed: code={code}, log={log}")]
11    Transaction { code: u32, log: String },
12
13    #[error("provider communication failed: {0}")]
14    Provider(String),
15
16    #[error("invalid SDL: {0}")]
17    Sdl(String),
18
19    #[error("manifest build failed: {0}")]
20    Manifest(String),
21
22    #[error("invalid workflow state: {0}")]
23    InvalidState(String),
24
25    #[error("storage error: {0}")]
26    Storage(String),
27
28    #[error("certificate error: {0}")]
29    Certificate(String),
30
31    #[error("JWT error: {0}")]
32    Jwt(String),
33
34    #[error("timeout: {0}")]
35    Timeout(String),
36
37    #[error("template error: {0}")]
38    Template(String),
39
40    #[error("signer error: {0}")]
41    Signer(String),
42}
43
44impl DeployError {
45    /// Whether this error might be recoverable by retry.
46    pub fn is_recoverable(&self) -> bool {
47        matches!(
48            self,
49            DeployError::Query(_) | DeployError::Provider(_) | DeployError::Timeout(_)
50        )
51    }
52}
53
54#[cfg(test)]
55mod tests {
56    use super::*;
57
58    #[test]
59    fn test_error_display() {
60        let err = DeployError::Query("connection failed".to_string());
61        assert_eq!(err.to_string(), "chain query failed: connection failed");
62
63        let err = DeployError::Transaction {
64            code: 5,
65            log: "insufficient funds".to_string(),
66        };
67        assert!(err.to_string().contains("code=5"));
68        assert!(err.to_string().contains("insufficient funds"));
69
70        let err = DeployError::Provider("404".to_string());
71        assert_eq!(err.to_string(), "provider communication failed: 404");
72
73        let err = DeployError::Sdl("invalid yaml".to_string());
74        assert_eq!(err.to_string(), "invalid SDL: invalid yaml");
75
76        let err = DeployError::Manifest("parsing failed".to_string());
77        assert_eq!(err.to_string(), "manifest build failed: parsing failed");
78
79        let err = DeployError::InvalidState("bad transition".to_string());
80        assert_eq!(err.to_string(), "invalid workflow state: bad transition");
81
82        let err = DeployError::Storage("disk full".to_string());
83        assert_eq!(err.to_string(), "storage error: disk full");
84
85        let err = DeployError::Certificate("expired".to_string());
86        assert_eq!(err.to_string(), "certificate error: expired");
87
88        let err = DeployError::Jwt("invalid signature".to_string());
89        assert_eq!(err.to_string(), "JWT error: invalid signature");
90
91        let err = DeployError::Timeout("30s".to_string());
92        assert_eq!(err.to_string(), "timeout: 30s");
93
94        let err = DeployError::Template("missing variable".to_string());
95        assert_eq!(err.to_string(), "template error: missing variable");
96    }
97
98    #[test]
99    fn test_error_is_recoverable() {
100        assert!(DeployError::Query("test".to_string()).is_recoverable());
101        assert!(DeployError::Provider("test".to_string()).is_recoverable());
102        assert!(DeployError::Timeout("test".to_string()).is_recoverable());
103
104        assert!(!DeployError::Sdl("test".to_string()).is_recoverable());
105        assert!(!DeployError::Manifest("test".to_string()).is_recoverable());
106        assert!(!DeployError::InvalidState("test".to_string()).is_recoverable());
107        assert!(!DeployError::Certificate("test".to_string()).is_recoverable());
108        assert!(!DeployError::Jwt("test".to_string()).is_recoverable());
109        assert!(!DeployError::Template("test".to_string()).is_recoverable());
110    }
111}