use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
#[serde(rename_all = "lowercase")]
pub enum HealthStatus {
#[default]
Ok,
Unhealthy,
}
impl HealthStatus {
pub fn ok() -> Self {
Self::Ok
}
pub fn unhealthy() -> Self {
Self::Unhealthy
}
pub fn is_ok(&self) -> bool {
self == &Self::Ok
}
}
#[derive(Debug, Serialize, Deserialize)]
#[serde(untagged)]
pub enum GetHealthResponse {
Simple(HealthStatus),
Detailed {
status: HealthStatus,
#[serde(skip_serializing_if = "Option::is_none")]
details: Option<HealthDetails>,
},
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum OracleHealthStatus {
Healthy,
Unhealthy,
Unknown,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct HealthDetails {
pub is_validator: bool,
pub consensus_running: bool,
pub subdag_processing_active: bool,
pub oracle_health: OracleHealthStatus,
pub latest_commit_round: u32,
pub latest_bank_slot: u64,
pub latest_bank_block_height: u64,
}
impl GetHealthResponse {
pub fn simple(status: HealthStatus) -> Self {
Self::Simple(status)
}
pub fn ok() -> Self {
Self::Simple(HealthStatus::Ok)
}
pub fn unhealthy() -> Self {
Self::Simple(HealthStatus::Unhealthy)
}
pub fn detailed(status: HealthStatus, details: HealthDetails) -> Self {
Self::Detailed {
status,
details: Some(details),
}
}
pub fn status(&self) -> HealthStatus {
match self {
Self::Simple(status) => status.clone(),
Self::Detailed { status, .. } => status.clone(),
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct GetHealthRequest {
#[serde(default, skip_serializing_if = "Option::is_none")]
pub detailed: Option<bool>,
}
impl GetHealthRequest {
pub fn new() -> Self {
Self { detailed: None }
}
pub fn with_detailed(detailed: bool) -> Self {
Self {
detailed: Some(detailed),
}
}
}
impl Default for GetHealthRequest {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use serde_json::{from_str, to_string};
use super::*;
#[test]
fn test_health_status_ok_serialization() {
let status = HealthStatus::Ok;
let json = to_string(&status).unwrap();
assert_eq!(json, "\"ok\"");
let deserialized: HealthStatus = from_str(&json).unwrap();
assert_eq!(deserialized, HealthStatus::Ok);
}
#[test]
fn test_health_status_unhealthy_serialization() {
let status = HealthStatus::Unhealthy;
let json = to_string(&status).unwrap();
assert_eq!(json, "\"unhealthy\"");
let deserialized: HealthStatus = from_str(&json).unwrap();
assert_eq!(deserialized, HealthStatus::Unhealthy);
}
#[test]
fn test_get_health_response_ok_serialization() {
let response = GetHealthResponse::ok();
let json = to_string(&response).unwrap();
assert_eq!(json, "\"ok\"");
let deserialized: GetHealthResponse = from_str(&json).unwrap();
match deserialized {
GetHealthResponse::Simple(status) => assert_eq!(status, HealthStatus::Ok),
_ => panic!("Expected simple response"),
}
}
#[test]
fn test_get_health_response_unhealthy_serialization() {
let response = GetHealthResponse::unhealthy();
let json = to_string(&response).unwrap();
assert_eq!(json, "\"unhealthy\"");
let deserialized: GetHealthResponse = from_str(&json).unwrap();
match deserialized {
GetHealthResponse::Simple(status) => assert_eq!(status, HealthStatus::Unhealthy),
_ => panic!("Expected simple response"),
}
}
#[test]
fn test_get_health_response_detailed_serialization() {
let details = HealthDetails {
is_validator: true,
consensus_running: true,
subdag_processing_active: true,
oracle_health: OracleHealthStatus::Healthy,
latest_commit_round: 100,
latest_bank_slot: 200,
latest_bank_block_height: 150,
};
let response = GetHealthResponse::detailed(HealthStatus::Ok, details);
let json = to_string(&response).unwrap();
let deserialized: GetHealthResponse = from_str(&json).unwrap();
match deserialized {
GetHealthResponse::Detailed { status, details } => {
assert_eq!(status, HealthStatus::Ok);
let details = details.expect("Expected details");
assert!(details.is_validator);
assert!(details.consensus_running);
assert_eq!(details.oracle_health, OracleHealthStatus::Healthy);
assert_eq!(details.latest_commit_round, 100);
}
_ => panic!("Expected detailed response"),
}
}
}