use std::path::PathBuf; fn fixture_path(rel: &str) -> PathBuf { PathBuf::from(env!("CARGO_MANIFEST_DIR")).join(rel) } fn run_offline_case(phase2_workers: Option) -> (serde_json::Value, Vec) { let db_dir = tempfile::tempdir().expect("db tempdir"); let out_dir = tempfile::tempdir().expect("out tempdir"); let report_path = out_dir.path().join("report.json"); let ccr_path = out_dir.path().join("result.ccr"); let mut argv = vec![ "rpki".to_string(), "--db".to_string(), db_dir.path().to_string_lossy().to_string(), "--tal-path".to_string(), fixture_path("tests/fixtures/tal/apnic-rfc7730-https.tal") .to_string_lossy() .to_string(), "--ta-path".to_string(), fixture_path("tests/fixtures/ta/apnic-ta.cer") .to_string_lossy() .to_string(), "--disable-rrdp".to_string(), "--rsync-local-dir".to_string(), fixture_path("tests/fixtures/repository") .to_string_lossy() .to_string(), "--validation-time".to_string(), "2026-04-07T00:00:00Z".to_string(), "--max-depth".to_string(), "4".to_string(), "--max-instances".to_string(), "64".to_string(), "--report-json".to_string(), report_path.to_string_lossy().to_string(), "--ccr-out".to_string(), ccr_path.to_string_lossy().to_string(), ]; if let Some(workers) = phase2_workers { argv.push("--parallel-phase2-object-workers".to_string()); argv.push(workers.to_string()); argv.push("--parallel-phase2-worker-queue-capacity".to_string()); argv.push("64".to_string()); } rpki::cli::run(&argv).expect("cli run"); let report_bytes = std::fs::read(&report_path).expect("read report"); let report: serde_json::Value = serde_json::from_slice(&report_bytes).expect("parse report"); let ccr_bytes = std::fs::read(&ccr_path).expect("read ccr"); (report, ccr_bytes) } #[test] fn offline_default_parallel_and_configured_phase2_match_compare_views() { let (default_report, default_ccr_bytes) = run_offline_case(None); let (configured_report, configured_ccr_bytes) = run_offline_case(Some(4)); let default_ccr = rpki::ccr::decode_content_info(&default_ccr_bytes).expect("decode default ccr"); let configured_ccr = rpki::ccr::decode_content_info(&configured_ccr_bytes).expect("decode configured ccr"); let (default_vrps, default_vaps) = rpki::bundle::decode_ccr_compare_views(&default_ccr, "apnic") .expect("default compare view"); let (configured_vrps, configured_vaps) = rpki::bundle::decode_ccr_compare_views(&configured_ccr, "apnic") .expect("configured compare view"); assert_eq!( default_vrps, configured_vrps, "VRP compare views must match" ); assert_eq!( default_vaps, configured_vaps, "VAP compare views must match" ); let default_points = default_report["publication_points"] .as_array() .expect("default publication_points"); let configured_points = configured_report["publication_points"] .as_array() .expect("configured publication_points"); assert_eq!( default_points.len(), configured_points.len(), "publication point counts must match" ); } #[test] fn offline_default_parallel_emits_online_ccr_accumulator_output() { let (report, ccr_bytes) = run_offline_case(None); let ccr = rpki::ccr::decode_content_info(&ccr_bytes).expect("decode ccr"); let (_vrps, _vaps) = rpki::bundle::decode_ccr_compare_views(&ccr, "apnic").expect("compare view"); assert!( report["publication_points"] .as_array() .expect("publication_points") .len() > 0, "default parallel replay must process publication points" ); }