use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use serde_json::Value;
#[derive(Serialize, Deserialize, Clone, Copy, Debug, PartialEq, Eq, Default)]
#[serde(rename_all = "lowercase")]
pub enum LifecycleType {
#[default]
Delete,
Compress,
}
#[repr(u8)]
#[derive(Serialize, Deserialize, Clone, Copy, Debug, PartialEq, Eq)]
#[serde(rename_all = "lowercase")]
pub enum LifecycleMode {
Enabled,
Disabled,
#[serde(rename = "dry_run")]
DryRun,
}
impl Default for LifecycleMode {
fn default() -> Self {
Self::Enabled
}
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
pub struct LifecycleSettings {
#[serde(rename = "type")]
pub lifecycle_type: LifecycleType,
pub bucket: String,
#[serde(default)]
pub entries: Vec<String>,
pub older_than: String,
#[serde(default = "default_lifecycle_interval")]
pub interval: String,
#[serde(default)]
pub when: Option<Value>,
#[serde(default)]
pub mode: LifecycleMode,
}
impl Default for LifecycleSettings {
fn default() -> Self {
Self {
lifecycle_type: LifecycleType::default(),
bucket: String::default(),
entries: Vec::default(),
older_than: String::default(),
interval: default_lifecycle_interval(),
when: Option::default(),
mode: LifecycleMode::default(),
}
}
}
fn default_lifecycle_interval() -> String {
"3600s".to_string()
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
pub struct LifecycleInfo {
pub name: String,
pub is_provisioned: bool,
pub is_running: bool,
#[serde(default, rename = "type")]
pub lifecycle_type: LifecycleType,
#[serde(default)]
pub mode: LifecycleMode,
#[serde(default)]
pub last_run: Option<DateTime<Utc>>,
}
#[derive(Serialize, Deserialize, Clone, Copy, Debug, PartialEq, Eq)]
pub struct LifecycleModePayload {
pub mode: LifecycleMode,
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Default)]
pub struct LifecycleList {
pub lifecycles: Vec<LifecycleInfo>,
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
pub struct FullLifecycleInfo {
pub info: LifecycleInfo,
pub settings: LifecycleSettings,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn lifecycle_mode_default_is_enabled() {
assert_eq!(LifecycleMode::default(), LifecycleMode::Enabled);
}
#[test]
fn lifecycle_mode_serde_roundtrip() {
assert_eq!(
serde_json::to_string(&LifecycleMode::Enabled).unwrap(),
"\"enabled\""
);
assert_eq!(
serde_json::to_string(&LifecycleMode::Disabled).unwrap(),
"\"disabled\""
);
assert_eq!(
serde_json::to_string(&LifecycleMode::DryRun).unwrap(),
"\"dry_run\""
);
assert_eq!(
serde_json::from_str::<LifecycleMode>("\"enabled\"").unwrap(),
LifecycleMode::Enabled
);
assert_eq!(
serde_json::from_str::<LifecycleMode>("\"disabled\"").unwrap(),
LifecycleMode::Disabled
);
assert_eq!(
serde_json::from_str::<LifecycleMode>("\"dry_run\"").unwrap(),
LifecycleMode::DryRun
);
}
#[test]
fn lifecycle_settings_mode_defaults_on_missing() {
let settings: LifecycleSettings = serde_json::from_str(
r#"{
"type": "delete",
"bucket": "bucket-1",
"entries": ["entry-1"],
"older_than": "1d",
"interval": "1h"
}"#,
)
.unwrap();
assert_eq!(settings.mode, LifecycleMode::Enabled);
}
#[test]
fn lifecycle_settings_type_is_required() {
let err = serde_json::from_str::<LifecycleSettings>(
r#"{
"bucket": "bucket-1",
"older_than": "1d"
}"#,
)
.unwrap_err();
assert!(err.to_string().contains("missing field `type`"));
}
#[test]
fn lifecycle_settings_default_interval_is_3600s() {
let settings = LifecycleSettings::default();
assert_eq!(settings.interval, "3600s");
}
#[test]
fn lifecycle_info_mode_defaults_on_missing() {
let info: LifecycleInfo = serde_json::from_str(
r#"{
"name": "test",
"is_provisioned": false,
"is_running": true
}"#,
)
.unwrap();
assert_eq!(info.lifecycle_type, LifecycleType::Delete);
assert_eq!(info.mode, LifecycleMode::Enabled);
assert_eq!(info.last_run, None);
}
#[test]
fn lifecycle_mode_payload_serde_roundtrip() {
let payload = LifecycleModePayload {
mode: LifecycleMode::Disabled,
};
let serialized = serde_json::to_string(&payload).unwrap();
assert_eq!(serialized, r#"{"mode":"disabled"}"#);
let deserialized: LifecycleModePayload = serde_json::from_str(&serialized).unwrap();
assert_eq!(deserialized, payload);
}
}