use std::path::{Path, PathBuf}; use crate::query_db::{ObjectInstanceRecord, QueryDb, QueryDbResult}; pub fn report_path_for_run(db: &QueryDb, run_id: &str) -> QueryDbResult> { Ok(db .get_run(run_id)? .map(|run| Path::new(&run.run_dir).join("report.json"))) } pub fn resolve_object_from_cache_or_report( _db: &QueryDb, _run_id: &str, ) -> QueryDbResult> { Ok(None) } #[cfg(test)] mod tests { use std::fs; use serde_json::json; use super::*; use crate::query_db::{ArtifactIndexerConfig, index_artifacts}; #[test] fn report_path_for_run_resolves_indexed_run_directory() { let temp = tempfile::tempdir().expect("tempdir"); let run_dir = temp.path().join("runs/run_0001"); fs::create_dir_all(&run_dir).expect("run dir"); write_sample_run(&run_dir); let query_db_path = temp.path().join("query-db"); index_artifacts(&ArtifactIndexerConfig { query_db_path: query_db_path.clone(), run_root: Some(temp.path().to_path_buf()), run_dir: None, repo_bytes_db_path: None, projection_entry_limit: 50, min_run_seq: None, retain_indexed_runs: None, }) .expect("index"); let db = QueryDb::open(&query_db_path).expect("open db"); assert_eq!( report_path_for_run(&db, "run_0001").expect("report path"), Some(run_dir.join("report.json")) ); assert!( report_path_for_run(&db, "missing") .expect("missing report path") .is_none() ); assert!( resolve_object_from_cache_or_report(&db, "run_0001") .expect("placeholder resolver") .is_none() ); } fn write_sample_run(run_dir: &Path) { let report = json!({ "format_version": 2, "meta": {"validation_time_rfc3339_utc": "2026-06-20T00:00:00Z"}, "tree": {"warnings": []}, "publication_points": [ { "node_id": 1, "rsync_base_uri": "rsync://repo.example/rpki/", "manifest_rsync_uri": "rsync://repo.example/rpki/m.mft", "publication_point_rsync_uri": "rsync://repo.example/rpki/", "rrdp_notification_uri": "https://repo.example/rrdp/notification.xml", "source": "rrdp", "repo_sync_source": "rrdp", "repo_sync_phase": "rrdp_delta", "repo_sync_duration_ms": 7, "repo_terminal_state": "fresh", "warnings": [], "objects": [ {"rsync_uri":"rsync://repo.example/rpki/m.mft","sha256_hex":"11","kind":"manifest","result":"ok"} ] } ], "vrps": [], "aspas": [], "downloads": [], "download_stats": {}, "repo_sync_stats": {} }); fs::write( run_dir.join("report.json"), serde_json::to_vec(&report).unwrap(), ) .expect("report"); let summary = json!({ "status": "success", "runId": "run_0001", "runSeq": 1, "startedAtRfc3339Utc": "2026-06-20T00:00:00Z", "finishedAtRfc3339Utc": "2026-06-20T00:00:01Z", "wallMs": 1000, "reportCounts": {"vrps": 0, "aspas": 0, "publicationPoints": 1, "warnings": 0} }); fs::write( run_dir.join("run-summary.json"), serde_json::to_vec(&summary).unwrap(), ) .expect("summary"); fs::write(run_dir.join("stage-timing.json"), b"{}").expect("stage"); } }