use std::collections::HashMap;
use serde::{Deserialize, Serialize};
#[derive(Debug, Serialize, Deserialize, utoipa::ToSchema)]
pub struct NodeSummary {
pub id: u64,
pub address: String,
pub status: String,
pub role: String,
pub labels: HashMap<String, String>,
pub last_seen: u64,
}
#[derive(Debug, Serialize, Deserialize, utoipa::ToSchema)]
pub struct NodeResourceInfo {
pub cpu_total: f64,
pub cpu_used: f64,
pub cpu_percent: f64,
pub memory_total: u64,
pub memory_used: u64,
pub memory_percent: f64,
}
#[derive(Debug, Serialize, Deserialize, utoipa::ToSchema)]
pub struct NodeDetails {
pub id: u64,
pub address: String,
pub status: String,
pub role: String,
pub labels: HashMap<String, String>,
pub last_seen: u64,
pub resources: NodeResourceInfo,
pub services: Vec<String>,
pub registered_at: u64,
pub last_heartbeat: u64,
}
#[derive(Debug, Deserialize, utoipa::ToSchema)]
pub struct UpdateLabelsRequest {
pub labels: HashMap<String, String>,
pub remove: Vec<String>,
}
#[derive(Debug, Serialize, Deserialize, utoipa::ToSchema)]
pub struct UpdateLabelsResponse {
pub labels: HashMap<String, String>,
}
#[derive(Debug, Serialize, Deserialize, utoipa::ToSchema)]
pub struct JoinTokenResponse {
pub token: String,
pub leader_endpoint: String,
pub leader_public_key: String,
pub overlay_cidr: String,
pub allocated_ip: String,
pub expires_at: u64,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_node_summary_serialize() {
let summary = NodeSummary {
id: 1,
address: "192.168.1.10:9090".to_string(),
status: "ready".to_string(),
role: "worker".to_string(),
labels: HashMap::from([("zone".to_string(), "us-east-1".to_string())]),
last_seen: 1_706_745_600,
};
let json = serde_json::to_string(&summary).unwrap();
assert!(json.contains("192.168.1.10"));
assert!(json.contains("ready"));
assert!(json.contains("worker"));
}
#[test]
fn test_node_details_serialize() {
let details = NodeDetails {
id: 1,
address: "192.168.1.10:9090".to_string(),
status: "ready".to_string(),
role: "worker".to_string(),
labels: HashMap::new(),
last_seen: 1_706_745_600,
resources: NodeResourceInfo {
cpu_total: 4.0,
cpu_used: 1.5,
cpu_percent: 37.5,
memory_total: 8_589_934_592,
memory_used: 4_294_967_296,
memory_percent: 50.0,
},
services: vec!["api".to_string(), "worker".to_string()],
registered_at: 1_706_659_200,
last_heartbeat: 1_706_745_600,
};
let json = serde_json::to_string(&details).unwrap();
assert!(json.contains("resources"));
assert!(json.contains("services"));
assert!(json.contains("cpu_total"));
}
#[test]
fn test_update_labels_request_deserialize() {
let json = r#"{"labels": {"zone": "us-west-2"}, "remove": ["old-label"]}"#;
let request: UpdateLabelsRequest = serde_json::from_str(json).unwrap();
assert_eq!(request.labels.get("zone"), Some(&"us-west-2".to_string()));
assert_eq!(request.remove, vec!["old-label".to_string()]);
}
#[test]
fn test_join_token_response_serialize() {
let response = JoinTokenResponse {
token: "abc123".to_string(),
leader_endpoint: "192.168.1.1:9090".to_string(),
leader_public_key: "pubkey".to_string(),
overlay_cidr: "10.0.0.0/16".to_string(),
allocated_ip: "10.0.1.5".to_string(),
expires_at: 1_706_832_000,
};
let json = serde_json::to_string(&response).unwrap();
assert!(json.contains("abc123"));
assert!(json.contains("overlay_cidr"));
}
}