pitchfork_cli/
daemon_status.rs1use serde::{Deserialize, Serialize};
2
3#[derive(Debug, Clone, Serialize, Deserialize, strum::Display, strum::EnumIs)]
4#[strum(serialize_all = "snake_case")]
5#[serde(rename_all = "snake_case")]
6#[derive(Default)]
7pub enum DaemonStatus {
8 Failed(String),
9 Waiting,
10 Running,
11 Stopping,
12 Errored(i32),
14 Completed,
26 #[default]
27 Stopped,
28}
29
30impl DaemonStatus {
31 pub fn style(&self) -> String {
32 let s = self.to_string();
33 match self {
34 DaemonStatus::Failed(_) => console::style(s).red().to_string(),
35 DaemonStatus::Waiting => console::style(s).yellow().to_string(),
36 DaemonStatus::Running => console::style(s).green().to_string(),
37 DaemonStatus::Stopping => console::style(s).yellow().to_string(),
38 DaemonStatus::Stopped => console::style(s).dim().to_string(),
39 DaemonStatus::Completed => console::style(s).green().dim().to_string(),
40 DaemonStatus::Errored(_) => console::style(s).red().to_string(),
41 }
42 }
43
44 pub fn error_message(&self) -> Option<String> {
45 match self {
46 DaemonStatus::Failed(msg) => Some(msg.clone()),
47 DaemonStatus::Errored(code) if *code != -1 => Some(format!("exit code {code}")),
48 DaemonStatus::Errored(_) => Some("unknown exit code".to_string()),
49 _ => None,
50 }
51 }
52}
53
54#[cfg(test)]
55mod tests {
56 use super::*;
57
58 fn all_variants() -> Vec<(&'static str, DaemonStatus)> {
59 vec![
60 ("running", DaemonStatus::Running),
61 ("stopped", DaemonStatus::Stopped),
62 ("waiting", DaemonStatus::Waiting),
63 ("stopping", DaemonStatus::Stopping),
64 ("failed", DaemonStatus::Failed("some error".to_string())),
65 ("errored", DaemonStatus::Errored(1)),
66 ("errored_unknown", DaemonStatus::Errored(-1)),
67 ("completed", DaemonStatus::Completed),
68 ]
69 }
70
71 #[test]
72 fn test_completed_serializes_as_completed() {
73 assert_eq!(DaemonStatus::Completed.to_string(), "completed");
76 assert_eq!(
77 serde_json::to_string(&DaemonStatus::Completed).unwrap(),
78 "\"completed\""
79 );
80 }
81
82 #[test]
83 fn test_completed_has_no_error_message() {
84 assert!(DaemonStatus::Completed.error_message().is_none());
85 }
86
87 #[test]
88 fn test_daemon_status_json_roundtrip() {
89 for (name, status) in all_variants() {
90 let json_str = serde_json::to_string(&status)
91 .unwrap_or_else(|_| panic!("Failed to serialize {name}"));
92 let result: Result<DaemonStatus, _> = serde_json::from_str(&json_str);
93 assert!(
94 result.is_ok(),
95 "Failed to deserialize {name}: {:?}",
96 result.err()
97 );
98 }
99 }
100
101 #[test]
102 fn test_daemon_status_toml_roundtrip() {
103 #[derive(Serialize, Deserialize, Debug)]
104 struct Wrapper {
105 status: DaemonStatus,
106 }
107
108 for (name, status) in all_variants() {
109 let w = Wrapper { status };
110 let toml_str =
111 toml::to_string(&w).unwrap_or_else(|e| panic!("Failed to serialize {name}: {e}"));
112 let result: Result<Wrapper, _> = toml::from_str(&toml_str);
113 assert!(
114 result.is_ok(),
115 "Failed to deserialize {name}: {:?}\nTOML was: {toml_str:?}",
116 result.err()
117 );
118 }
119 }
120}