fn test_CHECKPOINT_COV_hermetic_consistency_mismatched_hash() {
let temp_dir = TempDir::new().unwrap();
let mut store = CheckpointStore::new(temp_dir.path()).unwrap();
store.start_hermetic_run("app", "1.0", "hash123").unwrap();
let result = store.verify_hermetic_consistency("different");
assert!(result.is_err());
let err_msg = format!("{}", result.unwrap_err());
assert!(err_msg.contains("Lockfile drift"));
}
#[test]
fn test_CHECKPOINT_COV_is_hermetic_false_no_run() {
let temp_dir = TempDir::new().unwrap();
let store = CheckpointStore::new(temp_dir.path()).unwrap();
assert!(!store.is_hermetic());
}
#[test]
fn test_CHECKPOINT_COV_is_hermetic_false_normal_run() {
let temp_dir = TempDir::new().unwrap();
let mut store = CheckpointStore::new(temp_dir.path()).unwrap();
store.start_run("app", "1.0").unwrap();
assert!(!store.is_hermetic());
}
#[test]
fn test_CHECKPOINT_COV_is_hermetic_true() {
let temp_dir = TempDir::new().unwrap();
let mut store = CheckpointStore::new(temp_dir.path()).unwrap();
store.start_hermetic_run("app", "1.0", "h").unwrap();
assert!(store.is_hermetic());
}
#[test]
fn test_CHECKPOINT_COV_complete_run() {
let temp_dir = TempDir::new().unwrap();
let mut store = CheckpointStore::new(temp_dir.path()).unwrap();
store.start_run("app", "1.0").unwrap();
store.complete_run().unwrap();
let reloaded = CheckpointStore::load(temp_dir.path()).unwrap();
assert!(reloaded.current_run_id().is_some());
}
#[test]
fn test_CHECKPOINT_COV_complete_run_no_active_run() {
let temp_dir = TempDir::new().unwrap();
let mut store = CheckpointStore::new(temp_dir.path()).unwrap();
let result = store.complete_run();
assert!(result.is_ok());
}
#[test]
fn test_CHECKPOINT_COV_fail_step_marks_run_failed() {
let temp_dir = TempDir::new().unwrap();
let mut store = CheckpointStore::new(temp_dir.path()).unwrap();
store.start_run("app", "1.0").unwrap();
store.add_step("s1").unwrap();
store.start_step("s1").unwrap();
store.fail_step("s1", "disk full").unwrap();
let reloaded = CheckpointStore::load(temp_dir.path()).unwrap();
let step = reloaded.get_step("s1").unwrap();
assert_eq!(step.status, StepStatus::Failed);
assert_eq!(step.error_message.as_deref(), Some("disk full"));
}
#[test]
fn test_CHECKPOINT_COV_steps_accessor() {
let temp_dir = TempDir::new().unwrap();
let mut store = CheckpointStore::new(temp_dir.path()).unwrap();
store.start_run("app", "1.0").unwrap();
store.add_step("s1").unwrap();
store.add_step("s2").unwrap();
store.add_step("s3").unwrap();
let steps = store.steps();
assert_eq!(steps.len(), 3);
assert_eq!(steps[0].step_id, "s1");
assert_eq!(steps[1].step_id, "s2");
assert_eq!(steps[2].step_id, "s3");
}
#[test]
fn test_CHECKPOINT_COV_state_files_for_step_multiple() {
let temp_dir = TempDir::new().unwrap();
let mut store = CheckpointStore::new(temp_dir.path()).unwrap();
store.start_run("app", "1.0").unwrap();
store.add_step("s1").unwrap();
store
.track_file("s1", Path::new("/a.txt"), "hash-a")
.unwrap();
store
.track_file("s1", Path::new("/b.txt"), "hash-b")
.unwrap();
store
.track_file("s2", Path::new("/c.txt"), "hash-c")
.unwrap();
let files_s1 = store.state_files_for_step("s1");
assert_eq!(files_s1.len(), 2);
let files_s2 = store.state_files_for_step("s2");
assert_eq!(files_s2.len(), 1);
let files_s3 = store.state_files_for_step("nonexistent");
assert_eq!(files_s3.len(), 0);
}
#[test]
fn test_CHECKPOINT_COV_last_successful_step_none() {
let temp_dir = TempDir::new().unwrap();
let mut store = CheckpointStore::new(temp_dir.path()).unwrap();
store.start_run("app", "1.0").unwrap();
store.add_step("s1").unwrap();
assert!(store.last_successful_step().is_none());
}
#[test]
fn test_CHECKPOINT_COV_last_successful_step_all_failed() {
let temp_dir = TempDir::new().unwrap();
let mut store = CheckpointStore::new(temp_dir.path()).unwrap();
store.start_run("app", "1.0").unwrap();
store.add_step("s1").unwrap();
store.start_step("s1").unwrap();
store.fail_step("s1", "err").unwrap();
assert!(store.last_successful_step().is_none());
}
#[test]
fn test_CHECKPOINT_COV_last_successful_step_returns_latest() {
let temp_dir = TempDir::new().unwrap();
let mut store = CheckpointStore::new(temp_dir.path()).unwrap();
store.start_run("app", "1.0").unwrap();
store.add_step("s1").unwrap();
store.start_step("s1").unwrap();
store.complete_step("s1", None).unwrap();
store.add_step("s2").unwrap();
store.start_step("s2").unwrap();
store.complete_step("s2", Some("done".to_string())).unwrap();
store.add_step("s3").unwrap();
let last = store.last_successful_step().unwrap();
assert_eq!(last.step_id, "s2");
}
#[test]
fn test_CHECKPOINT_COV_get_step_found() {
let temp_dir = TempDir::new().unwrap();
let mut store = CheckpointStore::new(temp_dir.path()).unwrap();
store.start_run("app", "1.0").unwrap();
store.add_step("step-x").unwrap();
let step = store.get_step("step-x");
assert!(step.is_some());
assert_eq!(step.unwrap().step_id, "step-x");
}
#[test]
fn test_CHECKPOINT_COV_get_step_not_found() {
let temp_dir = TempDir::new().unwrap();
let mut store = CheckpointStore::new(temp_dir.path()).unwrap();
store.start_run("app", "1.0").unwrap();
let step = store.get_step("not-here");
assert!(step.is_none());
}
#[test]
fn test_CHECKPOINT_COV_load_creates_new_if_no_file() {
let temp_dir = TempDir::new().unwrap();
let store = CheckpointStore::load(temp_dir.path()).unwrap();
assert!(store.current_run_id().is_none());
assert_eq!(store.steps().len(), 0);
}
#[test]
fn test_CHECKPOINT_COV_persistence_full_roundtrip() {
let temp_dir = TempDir::new().unwrap();
{
let mut store = CheckpointStore::new(temp_dir.path()).unwrap();
store
.start_hermetic_run("my-app", "3.0.0", "lockhash")
.unwrap();
store.add_step("s1").unwrap();
store.start_step("s1").unwrap();
store
.complete_step("s1", Some("output1".to_string()))
.unwrap();
store.add_step("s2").unwrap();
store.start_step("s2").unwrap();
store.fail_step("s2", "disk full").unwrap();
store.add_step("s3").unwrap();
store
.track_file("s1", Path::new("/etc/conf"), "sha256:abc")
.unwrap();
}
{
let store = CheckpointStore::load(temp_dir.path()).unwrap();
assert!(store.current_run_id().is_some());
assert!(store.is_hermetic());
let s1 = store.get_step("s1").unwrap();
assert_eq!(s1.status, StepStatus::Completed);
assert_eq!(s1.output_log.as_deref(), Some("output1"));
let s2 = store.get_step("s2").unwrap();
assert_eq!(s2.status, StepStatus::Failed);
assert_eq!(s2.error_message.as_deref(), Some("disk full"));
let s3 = store.get_step("s3").unwrap();
assert_eq!(s3.status, StepStatus::Pending);
let files = store.state_files_for_step("s1");
assert_eq!(files.len(), 1);
assert_eq!(files[0].content_hash, "sha256:abc");
let last = store.last_successful_step().unwrap();
assert_eq!(last.step_id, "s1");
}
}
#[test]
fn test_CHECKPOINT_COV_start_run_clears_previous() {
let temp_dir = TempDir::new().unwrap();
let mut store = CheckpointStore::new(temp_dir.path()).unwrap();
store.start_run("app-1", "1.0").unwrap();
store.add_step("old-step").unwrap();
store
.track_file("old-step", Path::new("/old"), "hash")
.unwrap();
store.start_run("app-2", "2.0").unwrap();
assert_eq!(store.steps().len(), 0);
assert_eq!(store.state_files_for_step("old-step").len(), 0);
}