v0.3.6-pre.002
This commit is contained in:
153
crates/ksp-job-api/unit_tests/lifecycle.rs
Normal file
153
crates/ksp-job-api/unit_tests/lifecycle.rs
Normal file
@@ -0,0 +1,153 @@
|
||||
// file: crates/ksp-job-api/unit_tests/lifecycle.rs
|
||||
// version: 1
|
||||
|
||||
fn lifecycle() -> std::option::Option<crate::JobLifecycle> {
|
||||
let id = match crate::JobId::new("job-001") {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(_) => return std::option::Option::None,
|
||||
};
|
||||
let kind = match crate::JobKindCode::new("backfill_raw") {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(_) => return std::option::Option::None,
|
||||
};
|
||||
return std::option::Option::Some(crate::JobLifecycle::new(id, kind));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pre_002_lifecycle_accepts_every_planned_terminal_path() {
|
||||
for completion in [crate::JobCompletion::Complete, crate::JobCompletion::Partial] {
|
||||
let lifecycle = lifecycle();
|
||||
assert!(lifecycle.is_some());
|
||||
let mut lifecycle = match lifecycle {
|
||||
std::option::Option::Some(value) => value,
|
||||
std::option::Option::None => continue,
|
||||
};
|
||||
assert!(lifecycle.start().is_ok());
|
||||
assert!(lifecycle.complete(completion).is_ok());
|
||||
assert_eq!(lifecycle.state(), crate::JobState::Completed(completion));
|
||||
assert!(lifecycle.state().is_terminal());
|
||||
assert_eq!(lifecycle.state().completion(), std::option::Option::Some(completion));
|
||||
}
|
||||
let lifecycle = lifecycle();
|
||||
assert!(lifecycle.is_some());
|
||||
let mut lifecycle = match lifecycle {
|
||||
std::option::Option::Some(value) => value,
|
||||
std::option::Option::None => return,
|
||||
};
|
||||
assert!(lifecycle.start().is_ok());
|
||||
assert!(lifecycle.fail().is_ok());
|
||||
assert_eq!(lifecycle.state(), crate::JobState::Failed);
|
||||
let lifecycle = lifecycle();
|
||||
assert!(lifecycle.is_some());
|
||||
let mut lifecycle = match lifecycle {
|
||||
std::option::Option::Some(value) => value,
|
||||
std::option::Option::None => return,
|
||||
};
|
||||
assert!(lifecycle.mark_cancelled().is_ok());
|
||||
assert_eq!(lifecycle.state(), crate::JobState::Cancelled);
|
||||
return;
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pre_002_cancelling_allows_cancel_complete_or_fail() {
|
||||
for terminal in [crate::JobState::Cancelled, crate::JobState::Completed(crate::JobCompletion::Complete), crate::JobState::Failed] {
|
||||
let lifecycle = lifecycle();
|
||||
assert!(lifecycle.is_some());
|
||||
let mut lifecycle = match lifecycle {
|
||||
std::option::Option::Some(value) => value,
|
||||
std::option::Option::None => continue,
|
||||
};
|
||||
assert!(lifecycle.start().is_ok());
|
||||
assert!(lifecycle.mark_cancelling().is_ok());
|
||||
let result = match terminal {
|
||||
crate::JobState::Cancelled => lifecycle.mark_cancelled(),
|
||||
crate::JobState::Completed(completion) => lifecycle.complete(completion),
|
||||
crate::JobState::Failed => lifecycle.fail(),
|
||||
_ => return,
|
||||
};
|
||||
assert!(result.is_ok());
|
||||
assert_eq!(lifecycle.state(), terminal);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pre_002_invalid_transition_preserves_source_state_and_reports_safe_context() {
|
||||
let lifecycle = lifecycle();
|
||||
assert!(lifecycle.is_some());
|
||||
let mut lifecycle = match lifecycle {
|
||||
std::option::Option::Some(value) => value,
|
||||
std::option::Option::None => return,
|
||||
};
|
||||
let rejected = lifecycle.complete(crate::JobCompletion::Complete);
|
||||
assert!(rejected.is_err());
|
||||
assert_eq!(lifecycle.state(), crate::JobState::Created);
|
||||
let error = match rejected {
|
||||
std::result::Result::Err(value) => value,
|
||||
std::result::Result::Ok(_) => return,
|
||||
};
|
||||
assert_eq!(error.code(), crate::ERROR_CODE_JOB_TRANSITION_INVALID);
|
||||
assert_eq!(error.context().len(), 2);
|
||||
assert_eq!(error.context()[0].key(), "source_state");
|
||||
assert_eq!(error.context()[0].value(), "created");
|
||||
assert_eq!(error.context()[1].key(), "target_state");
|
||||
assert_eq!(error.context()[1].value(), "completed");
|
||||
return;
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pre_002_every_terminal_state_rejects_later_mutation() {
|
||||
let terminals = [crate::JobState::Completed(crate::JobCompletion::Complete), crate::JobState::Cancelled, crate::JobState::Failed];
|
||||
for terminal in terminals {
|
||||
let lifecycle = lifecycle();
|
||||
assert!(lifecycle.is_some());
|
||||
let mut lifecycle = match lifecycle {
|
||||
std::option::Option::Some(value) => value,
|
||||
std::option::Option::None => continue,
|
||||
};
|
||||
if terminal == crate::JobState::Cancelled {
|
||||
assert!(lifecycle.mark_cancelled().is_ok());
|
||||
} else {
|
||||
assert!(lifecycle.start().is_ok());
|
||||
let terminal_result = match terminal {
|
||||
crate::JobState::Completed(completion) => lifecycle.complete(completion),
|
||||
crate::JobState::Failed => lifecycle.fail(),
|
||||
_ => return,
|
||||
};
|
||||
assert!(terminal_result.is_ok());
|
||||
}
|
||||
let rejected = lifecycle.start();
|
||||
assert!(rejected.is_err());
|
||||
assert_eq!(lifecycle.state(), terminal);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pre_002_transition_matrix_is_exact() {
|
||||
let states = [
|
||||
crate::JobState::Created,
|
||||
crate::JobState::Running,
|
||||
crate::JobState::Cancelling,
|
||||
crate::JobState::Completed(crate::JobCompletion::Complete),
|
||||
crate::JobState::Cancelled,
|
||||
crate::JobState::Failed,
|
||||
];
|
||||
for source in states {
|
||||
for target in states {
|
||||
let expected = matches!(
|
||||
(source, target),
|
||||
(crate::JobState::Created, crate::JobState::Running)
|
||||
| (crate::JobState::Created, crate::JobState::Cancelled)
|
||||
| (crate::JobState::Running, crate::JobState::Cancelling)
|
||||
| (crate::JobState::Running, crate::JobState::Completed(_))
|
||||
| (crate::JobState::Running, crate::JobState::Failed)
|
||||
| (crate::JobState::Cancelling, crate::JobState::Completed(_))
|
||||
| (crate::JobState::Cancelling, crate::JobState::Cancelled)
|
||||
| (crate::JobState::Cancelling, crate::JobState::Failed)
|
||||
);
|
||||
assert_eq!(super::allowed_transition(source, target), expected, "unexpected transition matrix result for {source:?} -> {target:?}");
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
Reference in New Issue
Block a user