use crate::{AppError, ErrorCode};
const PERSISTENT_START_ERROR_KIND_DETAIL: &str = "rskit_process.persistent_start_error_kind";
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
#[non_exhaustive]
pub enum PersistentStartErrorKind {
SpawnFailed,
ReadinessCommandTimedOut,
ReadinessCommandFailed,
ReadinessTimedOut,
OutputEndedBeforeReadiness,
ExitedBeforeReadiness,
}
impl PersistentStartErrorKind {
const fn as_str(self) -> &'static str {
match self {
Self::SpawnFailed => "spawn_failed",
Self::ReadinessCommandTimedOut => "readiness_command_timed_out",
Self::ReadinessCommandFailed => "readiness_command_failed",
Self::ReadinessTimedOut => "readiness_timed_out",
Self::OutputEndedBeforeReadiness => "output_ended_before_readiness",
Self::ExitedBeforeReadiness => "exited_before_readiness",
}
}
fn from_str(value: &str) -> Option<Self> {
match value {
"spawn_failed" => Some(Self::SpawnFailed),
"readiness_command_timed_out" => Some(Self::ReadinessCommandTimedOut),
"readiness_command_failed" => Some(Self::ReadinessCommandFailed),
"readiness_timed_out" => Some(Self::ReadinessTimedOut),
"output_ended_before_readiness" => Some(Self::OutputEndedBeforeReadiness),
"exited_before_readiness" => Some(Self::ExitedBeforeReadiness),
_ => None,
}
}
}
pub fn persistent_start_error_kind(error: &AppError) -> Option<PersistentStartErrorKind> {
error
.details()
.get(PERSISTENT_START_ERROR_KIND_DETAIL)
.and_then(|value| value.as_str())
.and_then(PersistentStartErrorKind::from_str)
}
pub(in crate::persistent) fn persistent_start_error(
kind: PersistentStartErrorKind,
code: ErrorCode,
message: impl Into<String>,
) -> AppError {
AppError::new(code, message).with_detail(PERSISTENT_START_ERROR_KIND_DETAIL, kind.as_str())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn persistent_start_error_round_trips_all_structured_kinds() {
for kind in [
PersistentStartErrorKind::SpawnFailed,
PersistentStartErrorKind::ReadinessCommandTimedOut,
PersistentStartErrorKind::ReadinessCommandFailed,
PersistentStartErrorKind::ReadinessTimedOut,
PersistentStartErrorKind::OutputEndedBeforeReadiness,
PersistentStartErrorKind::ExitedBeforeReadiness,
] {
let error = persistent_start_error(kind, ErrorCode::Internal, "failed");
assert_eq!(persistent_start_error_kind(&error), Some(kind));
}
}
#[test]
fn missing_or_unknown_persistent_error_kind_returns_none() {
assert_eq!(
persistent_start_error_kind(&AppError::new(ErrorCode::Internal, "plain")),
None
);
let error = AppError::new(ErrorCode::Internal, "bad")
.with_detail(PERSISTENT_START_ERROR_KIND_DETAIL, "unknown");
assert_eq!(persistent_start_error_kind(&error), None);
}
}