use sysknife_types::JobState;
pub fn allowed_transition(current: &JobState, next: &JobState) -> bool {
matches!(
(current, next),
(JobState::Queued, JobState::Running)
| (JobState::Queued, JobState::Canceled)
| (JobState::Running, JobState::Succeeded)
| (JobState::Running, JobState::Failed)
| (JobState::Running, JobState::Canceled)
| (JobState::Running, JobState::RolledBack)
| (JobState::Running, JobState::NeedsReboot)
)
}
pub fn is_terminal(state: &JobState) -> bool {
matches!(
state,
JobState::Succeeded
| JobState::Failed
| JobState::Canceled
| JobState::RolledBack
| JobState::NeedsReboot
)
}
#[cfg(test)]
mod tests {
use super::*;
const ALL: &[JobState] = &[
JobState::Queued,
JobState::Running,
JobState::Succeeded,
JobState::Failed,
JobState::Canceled,
JobState::RolledBack,
JobState::NeedsReboot,
];
const ALLOWED: &[(JobState, JobState)] = &[
(JobState::Queued, JobState::Running),
(JobState::Queued, JobState::Canceled),
(JobState::Running, JobState::Succeeded),
(JobState::Running, JobState::Failed),
(JobState::Running, JobState::Canceled),
(JobState::Running, JobState::RolledBack),
(JobState::Running, JobState::NeedsReboot),
];
#[test]
fn every_permitted_edge_is_allowed() {
for (from, to) in ALLOWED {
assert!(
allowed_transition(from, to),
"{from:?} -> {to:?} must be permitted"
);
}
}
#[test]
fn every_other_edge_is_refused() {
for from in ALL {
for to in ALL {
let permitted = ALLOWED.iter().any(|(f, t)| f == from && t == to);
assert_eq!(
allowed_transition(from, to),
permitted,
"{from:?} -> {to:?}"
);
}
}
}
#[test]
fn terminal_states_cannot_be_left() {
for from in ALL.iter().filter(|s| is_terminal(s)) {
for to in ALL {
assert!(
!allowed_transition(from, to),
"terminal {from:?} must not transition to {to:?}"
);
}
}
}
#[test]
fn queued_and_running_are_not_terminal() {
assert!(!is_terminal(&JobState::Queued));
assert!(!is_terminal(&JobState::Running));
}
#[test]
fn a_job_cannot_restart_after_finishing() {
assert!(!allowed_transition(
&JobState::NeedsReboot,
&JobState::Running
));
assert!(!allowed_transition(
&JobState::Succeeded,
&JobState::Running
));
assert!(!allowed_transition(&JobState::Canceled, &JobState::Running));
}
}