use cuttlefish_host::ledger::Ledger;
use std::sync::Mutex;
static ENV_GUARD: Mutex<()> = Mutex::new(());
#[test]
fn a_fresh_ledger_has_no_checkpoints() {
let dir = tempfile::tempdir().unwrap();
let ledger = Ledger::open(&dir.path().join("ledger.sqlite"), "test-fingerprint").unwrap();
assert_eq!(ledger.get_completed("some_node").unwrap(), None);
}
#[test]
fn a_completed_checkpoint_round_trips() {
let dir = tempfile::tempdir().unwrap();
let ledger = Ledger::open(&dir.path().join("ledger.sqlite"), "test-fingerprint").unwrap();
let output = serde_json::json!({"summary": "hi"});
ledger.write_completed("summarize", &output).unwrap();
assert_eq!(ledger.get_completed("summarize").unwrap(), Some(output));
}
#[test]
fn a_skipped_checkpoint_has_no_output_but_is_recorded() {
let dir = tempfile::tempdir().unwrap();
let ledger = Ledger::open(&dir.path().join("ledger.sqlite"), "test-fingerprint").unwrap();
ledger.write_skipped("handle_pdf").unwrap();
assert!(ledger.is_skipped("handle_pdf").unwrap());
assert_eq!(ledger.get_completed("handle_pdf").unwrap(), None);
}
#[test]
fn job_status_starts_running_and_can_be_finalized() {
let dir = tempfile::tempdir().unwrap();
let ledger = Ledger::open(&dir.path().join("ledger.sqlite"), "test-fingerprint").unwrap();
assert_eq!(
ledger.job_status().unwrap(),
cuttlefish_host::ledger::LedgerJobStatus::Running
);
ledger.finish("completed").unwrap();
assert_eq!(
ledger.job_status().unwrap(),
cuttlefish_host::ledger::LedgerJobStatus::Completed
);
}
#[test]
fn reopening_an_existing_ledger_preserves_its_checkpoints() {
let dir = tempfile::tempdir().unwrap();
let path = dir.path().join("ledger.sqlite");
{
let ledger = Ledger::open(&path, "test-fingerprint").unwrap();
ledger.write_completed("a", &serde_json::json!(1)).unwrap();
}
let reopened = Ledger::open(&path, "test-fingerprint").unwrap();
assert_eq!(
reopened.get_completed("a").unwrap(),
Some(serde_json::json!(1))
);
}
#[test]
fn a_real_database_error_is_not_silently_treated_as_no_checkpoint() {
let dir = tempfile::tempdir().unwrap();
let path = dir.path().join("ledger.sqlite");
let ledger = Ledger::open(&path, "test-fingerprint").unwrap();
let corrupter = rusqlite::Connection::open(&path).unwrap();
corrupter.execute("DROP TABLE checkpoints", []).unwrap();
drop(corrupter);
let completed = ledger.get_completed("some_node");
assert!(
completed.is_err(),
"expected a real database error, got {completed:?}"
);
assert!(
!matches!(completed, Err(rusqlite::Error::QueryReturnedNoRows)),
"get_completed must not report a genuine error as QueryReturnedNoRows: {completed:?}"
);
let skipped = ledger.is_skipped("some_node");
assert!(
skipped.is_err(),
"expected a real database error, got {skipped:?}"
);
assert!(
!matches!(skipped, Err(rusqlite::Error::QueryReturnedNoRows)),
"is_skipped must not report a genuine error as QueryReturnedNoRows: {skipped:?}"
);
}
#[test]
fn reopening_with_a_different_fingerprint_keeps_the_original() {
let dir = tempfile::tempdir().unwrap();
let path = dir.path().join("ledger.sqlite");
Ledger::open(&path, "original").unwrap();
let reopened = Ledger::open(&path, "different").unwrap();
assert_eq!(reopened.graph_fingerprint().unwrap(), "original");
}
#[test]
fn jobs_root_honors_cuttlefish_jobs_home_when_set() {
let _guard = ENV_GUARD.lock().unwrap();
std::env::set_var("CUTTLEFISH_JOBS_HOME", "/tmp/cf-jobs-test");
let root = cuttlefish_host::ledger::jobs_root();
std::env::remove_var("CUTTLEFISH_JOBS_HOME");
assert_eq!(root, Some(std::path::PathBuf::from("/tmp/cf-jobs-test")));
}
#[test]
fn jobs_root_falls_back_to_cuttlefish_home_jobs_when_unset() {
let _guard = ENV_GUARD.lock().unwrap();
std::env::remove_var("CUTTLEFISH_JOBS_HOME");
std::env::set_var("CUTTLEFISH_HOME", "/tmp/cf-home-test");
let root = cuttlefish_host::ledger::jobs_root();
std::env::remove_var("CUTTLEFISH_HOME");
assert_eq!(
root,
Some(std::path::PathBuf::from("/tmp/cf-home-test/jobs"))
);
}