use serde::{Deserialize, Serialize};
use utoipa::ToSchema;
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, ToSchema)]
pub struct DiskUsageCategory {
pub name: String,
pub total_bytes: u64,
pub reclaimable_bytes: u64,
pub item_count: u64,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Default, ToSchema)]
pub struct SystemDiskUsage {
pub categories: Vec<DiskUsageCategory>,
pub total_bytes: u64,
pub total_reclaimable_bytes: u64,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Default, ToSchema)]
pub struct SystemPruneReport {
pub stopped_containers: Vec<String>,
pub dead_deployments: Vec<String>,
pub deleted_images: Vec<String>,
pub deleted_volumes: Vec<String>,
pub deleted_networks: Vec<String>,
pub reclaimed_layers: Vec<String>,
pub reclaimed_blobs: Vec<String>,
pub reclaimed_bundles: Vec<String>,
pub space_reclaimed_bytes: u64,
}
impl SystemPruneReport {
#[must_use]
pub fn total_items(&self) -> usize {
self.stopped_containers.len()
+ self.dead_deployments.len()
+ self.deleted_images.len()
+ self.deleted_volumes.len()
+ self.deleted_networks.len()
+ self.reclaimed_layers.len()
+ self.reclaimed_blobs.len()
+ self.reclaimed_bundles.len()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_system_disk_usage_roundtrip() {
let usage = SystemDiskUsage {
categories: vec![
DiskUsageCategory {
name: "images".to_string(),
total_bytes: 10_000,
reclaimable_bytes: 2_500,
item_count: 7,
},
DiskUsageCategory {
name: "layers".to_string(),
total_bytes: 40_000,
reclaimable_bytes: 5_000,
item_count: 23,
},
],
total_bytes: 50_000,
total_reclaimable_bytes: 7_500,
};
let json = serde_json::to_string(&usage).unwrap();
assert!(json.contains("\"images\""));
assert!(json.contains("\"total_bytes\":50000"));
assert!(json.contains("\"total_reclaimable_bytes\":7500"));
let back: SystemDiskUsage = serde_json::from_str(&json).unwrap();
assert_eq!(back, usage);
}
#[test]
fn test_system_disk_usage_default() {
let usage = SystemDiskUsage::default();
assert!(usage.categories.is_empty());
assert_eq!(usage.total_bytes, 0);
assert_eq!(usage.total_reclaimable_bytes, 0);
}
#[test]
fn test_system_prune_report_roundtrip() {
let report = SystemPruneReport {
stopped_containers: vec!["c1".to_string(), "c2".to_string()],
dead_deployments: vec!["dep-old".to_string()],
deleted_images: vec!["nginx:latest".to_string()],
deleted_volumes: vec!["vol-a".to_string()],
deleted_networks: vec![],
reclaimed_layers: vec!["sha256:aaa".to_string(), "sha256:bbb".to_string()],
reclaimed_blobs: vec!["sha256:ccc".to_string()],
reclaimed_bundles: vec!["bundle-1".to_string()],
space_reclaimed_bytes: 123_456,
};
let json = serde_json::to_string(&report).unwrap();
let back: SystemPruneReport = serde_json::from_str(&json).unwrap();
assert_eq!(back, report);
assert!(json.contains("\"space_reclaimed_bytes\":123456"));
}
#[test]
fn test_system_prune_report_total_items() {
let report = SystemPruneReport {
stopped_containers: vec!["c1".to_string(), "c2".to_string()],
dead_deployments: vec!["dep-old".to_string()],
deleted_images: vec!["nginx:latest".to_string()],
deleted_volumes: vec!["vol-a".to_string()],
deleted_networks: vec!["net-1".to_string()],
reclaimed_layers: vec!["sha256:aaa".to_string(), "sha256:bbb".to_string()],
reclaimed_blobs: vec!["sha256:ccc".to_string()],
reclaimed_bundles: vec!["bundle-1".to_string()],
space_reclaimed_bytes: 0,
};
assert_eq!(report.total_items(), 10);
}
#[test]
fn test_system_prune_report_default_empty() {
let report = SystemPruneReport::default();
assert_eq!(report.total_items(), 0);
assert_eq!(report.space_reclaimed_bytes, 0);
}
}