1use chrono::{DateTime, Utc};
5use serde::{Deserialize, Serialize};
6use serde_json::Value;
7
8#[derive(Serialize, Deserialize, Clone, Copy, Debug, PartialEq, Eq, Default)]
10#[serde(rename_all = "lowercase")]
11pub enum LifecycleType {
12 #[default]
14 Delete,
15 Compress,
17}
18
19#[repr(u8)]
21#[derive(Serialize, Deserialize, Clone, Copy, Debug, PartialEq, Eq)]
22#[serde(rename_all = "lowercase")]
23pub enum LifecycleMode {
24 Enabled,
26 Disabled,
28 #[serde(rename = "dry_run")]
30 DryRun,
31}
32
33impl Default for LifecycleMode {
34 fn default() -> Self {
35 Self::Enabled
36 }
37}
38
39#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
41pub struct LifecycleSettings {
42 #[serde(rename = "type")]
44 pub lifecycle_type: LifecycleType,
45 pub bucket: String,
47 #[serde(default)]
51 pub entries: Vec<String>,
52 pub older_than: String,
54 #[serde(default = "default_lifecycle_interval")]
56 pub interval: String,
57 #[serde(default)]
59 pub when: Option<Value>,
60 #[serde(default)]
63 pub processing_interval: Option<String>,
64 #[serde(default)]
66 pub mode: LifecycleMode,
67}
68
69impl Default for LifecycleSettings {
70 fn default() -> Self {
71 Self {
72 lifecycle_type: LifecycleType::default(),
73 bucket: String::default(),
74 entries: Vec::default(),
75 older_than: String::default(),
76 interval: default_lifecycle_interval(),
77 when: Option::default(),
78 processing_interval: Option::default(),
79 mode: LifecycleMode::default(),
80 }
81 }
82}
83
84fn default_lifecycle_interval() -> String {
85 "3600s".to_string()
86}
87
88#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
90pub struct LifecycleInfo {
91 pub name: String,
93 pub is_provisioned: bool,
95 pub is_running: bool,
97 #[serde(default, rename = "type")]
99 pub lifecycle_type: LifecycleType,
100 #[serde(default)]
102 pub mode: LifecycleMode,
103 #[serde(default)]
105 pub last_run: Option<DateTime<Utc>>,
106}
107
108#[derive(Serialize, Deserialize, Clone, Copy, Debug, PartialEq, Eq)]
110pub struct LifecycleModePayload {
111 pub mode: LifecycleMode,
112}
113
114#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Default)]
116pub struct LifecycleList {
117 pub lifecycles: Vec<LifecycleInfo>,
119}
120
121#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
123pub struct FullLifecycleInfo {
124 pub info: LifecycleInfo,
126 pub settings: LifecycleSettings,
128}
129
130#[cfg(test)]
131mod tests {
132 use super::*;
133
134 #[test]
135 fn lifecycle_mode_default_is_enabled() {
136 assert_eq!(LifecycleMode::default(), LifecycleMode::Enabled);
137 }
138
139 #[test]
140 fn lifecycle_mode_serde_roundtrip() {
141 assert_eq!(
142 serde_json::to_string(&LifecycleMode::Enabled).unwrap(),
143 "\"enabled\""
144 );
145 assert_eq!(
146 serde_json::to_string(&LifecycleMode::Disabled).unwrap(),
147 "\"disabled\""
148 );
149 assert_eq!(
150 serde_json::to_string(&LifecycleMode::DryRun).unwrap(),
151 "\"dry_run\""
152 );
153
154 assert_eq!(
155 serde_json::from_str::<LifecycleMode>("\"enabled\"").unwrap(),
156 LifecycleMode::Enabled
157 );
158 assert_eq!(
159 serde_json::from_str::<LifecycleMode>("\"disabled\"").unwrap(),
160 LifecycleMode::Disabled
161 );
162 assert_eq!(
163 serde_json::from_str::<LifecycleMode>("\"dry_run\"").unwrap(),
164 LifecycleMode::DryRun
165 );
166 }
167
168 #[test]
169 fn lifecycle_settings_mode_defaults_on_missing() {
170 let settings: LifecycleSettings = serde_json::from_str(
171 r#"{
172 "type": "delete",
173 "bucket": "bucket-1",
174 "entries": ["entry-1"],
175 "older_than": "1d",
176 "interval": "1h"
177 }"#,
178 )
179 .unwrap();
180
181 assert_eq!(settings.mode, LifecycleMode::Enabled);
182 }
183
184 #[test]
185 fn lifecycle_settings_processing_interval_defaults_to_none() {
186 let settings: LifecycleSettings = serde_json::from_str(
187 r#"{
188 "type": "delete",
189 "bucket": "bucket-1",
190 "older_than": "1d"
191 }"#,
192 )
193 .unwrap();
194
195 assert_eq!(settings.processing_interval, None);
196 }
197
198 #[test]
199 fn lifecycle_settings_processing_interval_roundtrip() {
200 let settings: LifecycleSettings = serde_json::from_str(
201 r#"{
202 "type": "delete",
203 "bucket": "bucket-1",
204 "older_than": "1d",
205 "processing_interval": "12h"
206 }"#,
207 )
208 .unwrap();
209
210 assert_eq!(settings.processing_interval, Some("12h".to_string()));
211
212 let serialized = serde_json::to_string(&settings).unwrap();
213 let deserialized: LifecycleSettings = serde_json::from_str(&serialized).unwrap();
214 assert_eq!(deserialized, settings);
215 }
216
217 #[test]
218 fn lifecycle_settings_type_is_required() {
219 let err = serde_json::from_str::<LifecycleSettings>(
220 r#"{
221 "bucket": "bucket-1",
222 "older_than": "1d"
223 }"#,
224 )
225 .unwrap_err();
226
227 assert!(err.to_string().contains("missing field `type`"));
228 }
229
230 #[test]
231 fn lifecycle_settings_default_interval_is_3600s() {
232 let settings = LifecycleSettings::default();
233 assert_eq!(settings.interval, "3600s");
234 }
235
236 #[test]
237 fn lifecycle_info_mode_defaults_on_missing() {
238 let info: LifecycleInfo = serde_json::from_str(
239 r#"{
240 "name": "test",
241 "is_provisioned": false,
242 "is_running": true
243 }"#,
244 )
245 .unwrap();
246
247 assert_eq!(info.lifecycle_type, LifecycleType::Delete);
248 assert_eq!(info.mode, LifecycleMode::Enabled);
249 assert_eq!(info.last_run, None);
250 }
251
252 #[test]
253 fn lifecycle_mode_payload_serde_roundtrip() {
254 let payload = LifecycleModePayload {
255 mode: LifecycleMode::Disabled,
256 };
257
258 let serialized = serde_json::to_string(&payload).unwrap();
259 assert_eq!(serialized, r#"{"mode":"disabled"}"#);
260
261 let deserialized: LifecycleModePayload = serde_json::from_str(&serialized).unwrap();
262 assert_eq!(deserialized, payload);
263 }
264}