use std::collections::HashMap;
use chrono::{DateTime, Utc};
use crate::state::WorkloadState;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct DeployResult {
pub id: String,
pub name: String,
pub state: WorkloadState,
}
#[derive(Debug, Clone, Default, PartialEq, Eq)]
pub struct WaitResult {
pub status_code: i64,
pub error: Option<String>,
}
#[derive(Debug, Clone, Default, PartialEq, Eq)]
pub struct WorkloadStatus {
pub id: String,
pub name: String,
pub image: String,
pub state: WorkloadState,
pub running: bool,
pub healthy: bool,
pub ready: bool,
pub started_at: Option<DateTime<Utc>>,
pub stopped_at: Option<DateTime<Utc>>,
pub exit_code: Option<i32>,
pub message: String,
pub restarts: u32,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct WorkloadInfo {
pub id: String,
pub name: String,
pub image: String,
pub state: WorkloadState,
pub labels: HashMap<String, String>,
pub created: DateTime<Utc>,
pub namespace: String,
}
#[derive(Debug, Clone, Default, PartialEq)]
pub struct WorkloadStats {
pub cpu_percent: f64,
pub memory_usage: i64,
pub memory_limit: i64,
pub network_rx_bytes: i64,
pub network_tx_bytes: i64,
pub disk_read_bytes: i64,
pub disk_write_bytes: i64,
pub pids: i64,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct WorkloadEvent {
pub id: String,
pub name: String,
pub event: String,
pub timestamp: DateTime<Utc>,
pub message: String,
}
#[derive(Debug, Clone, Default, PartialEq, Eq)]
pub struct ExecResult {
pub exit_code: i32,
pub stdout: String,
pub stderr: String,
}
#[derive(Debug, Clone, Default, PartialEq, Eq)]
pub struct SystemInfo {
pub os: String,
pub architecture: String,
pub total_memory_mb: i64,
pub cpus: u32,
pub storage_driver: String,
pub runtime_version: String,
pub kernel_version: String,
pub operating_system: String,
pub gpus: Vec<GpuInfo>,
}
#[derive(Debug, Clone, Default, PartialEq, Eq)]
pub struct GpuInfo {
pub name: String,
pub memory_mb: i64,
pub driver_version: String,
}
#[derive(Debug, Clone, Default, PartialEq, Eq)]
pub struct DiskUsage {
pub images_size: i64,
pub containers_size: i64,
pub volumes_size: i64,
pub build_cache_size: i64,
pub data_root_path: String,
pub data_root_total: i64,
pub data_root_free: i64,
pub images: Vec<ImageDiskEntry>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ImageDiskEntry {
pub id: String,
pub repo_tags: Vec<String>,
pub size: i64,
pub shared_size: i64,
pub created: DateTime<Utc>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ImageDetail {
pub id: String,
pub repo_tags: Vec<String>,
pub repo_digests: Vec<String>,
pub size: i64,
pub architecture: String,
pub os: String,
pub created: DateTime<Utc>,
pub config: ImageConfig,
pub layers: Vec<String>,
}
#[derive(Debug, Clone, Default, PartialEq, Eq)]
pub struct ImageConfig {
pub env: Vec<String>,
pub labels: HashMap<String, String>,
pub cmd: Vec<String>,
pub entrypoint: Vec<String>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ImageEvent {
pub action: String,
pub image_ref: String,
pub image_id: String,
pub timestamp: DateTime<Utc>,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn status_default_state_is_unknown() {
let status = WorkloadStatus::default();
assert_eq!(status.state, WorkloadState::Unknown);
assert!(status.started_at.is_none());
assert!(status.exit_code.is_none());
}
#[test]
fn deploy_result_carries_initial_state() {
let result = DeployResult {
id: "abc123".into(),
name: "api".into(),
state: WorkloadState::Running,
};
assert!(result.state.is_running());
}
#[test]
fn wait_result_default_is_success() {
let result = WaitResult::default();
assert_eq!(result.status_code, 0);
assert!(result.error.is_none());
}
#[test]
fn system_info_default_is_empty() {
let info = SystemInfo::default();
assert_eq!(info.cpus, 0);
assert!(info.gpus.is_empty());
}
#[test]
fn disk_usage_carries_image_breakdown() {
let usage = DiskUsage {
images_size: 2048,
images: vec![ImageDiskEntry {
id: "img1".into(),
repo_tags: vec!["nginx:latest".into()],
size: 1024,
shared_size: 512,
created: Utc::now(),
}],
..Default::default()
};
assert_eq!(usage.images.len(), 1);
assert_eq!(usage.images[0].size, 1024);
}
#[test]
fn image_detail_holds_config_and_layers() {
let detail = ImageDetail {
id: "img1".into(),
repo_tags: vec!["nginx:latest".into()],
repo_digests: Vec::new(),
size: 4096,
architecture: "amd64".into(),
os: "linux".into(),
created: Utc::now(),
config: ImageConfig {
env: vec!["PATH=/usr/bin".into()],
..Default::default()
},
layers: vec!["sha256:layer".into()],
};
assert_eq!(detail.config.env.len(), 1);
assert_eq!(detail.layers.len(), 1);
}
#[test]
fn image_event_records_action() {
let event = ImageEvent {
action: "pull".into(),
image_ref: "nginx:latest".into(),
image_id: "sha256:abc".into(),
timestamp: Utc::now(),
};
assert_eq!(event.action, "pull");
}
#[test]
fn gpu_info_default_is_empty() {
assert_eq!(GpuInfo::default().memory_mb, 0);
}
}