rpki/tests/test_run_m9.rs
2026-02-11 10:07:24 +08:00

116 lines
3.9 KiB
Rust

use std::path::Path;
use rpki::data_model::crl::RpkixCrl;
use rpki::data_model::manifest::ManifestObject;
use rpki::data_model::rc::ResourceCertificate;
use rpki::fetch::rsync::LocalDirRsyncFetcher;
use rpki::policy::{Policy, SyncPreference};
use rpki::storage::RocksStore;
use rpki::sync::rrdp::Fetcher;
use rpki::validation::run::{fetch_cache_pp_exists, run_publication_point_once};
fn fixture_to_rsync_uri(path: &Path) -> String {
let rel = path
.strip_prefix("tests/fixtures/repository")
.expect("path under tests/fixtures/repository");
let mut it = rel.components();
let host = it
.next()
.expect("host component")
.as_os_str()
.to_string_lossy();
let rest = it.as_path().to_string_lossy();
format!("rsync://{host}/{rest}")
}
fn fixture_dir_to_rsync_uri(dir: &Path) -> String {
let mut s = fixture_to_rsync_uri(dir);
if !s.ends_with('/') {
s.push('/');
}
s
}
struct NeverHttpFetcher;
impl Fetcher for NeverHttpFetcher {
fn fetch(&self, _uri: &str) -> Result<Vec<u8>, String> {
Err("http fetch disabled in offline test".to_string())
}
}
#[test]
fn e2e_offline_uses_rsync_then_writes_fetch_cache_pp_then_outputs_vrps() {
let fixture_dir = Path::new("tests/fixtures/repository/rpki.cernet.net/repo/cernet/0");
let rsync_base_uri = "rsync://rpki.cernet.net/repo/cernet/0/";
let manifest_path = fixture_dir.join("05FC9C5B88506F7C0D3F862C8895BED67E9F8EBA.mft");
let manifest_rsync_uri = fixture_to_rsync_uri(&manifest_path);
let publication_point_rsync_uri = fixture_dir_to_rsync_uri(fixture_dir);
let issuer_ca_der = std::fs::read("tests/fixtures/repository/rpki.apnic.net/repository/B527EF581D6611E2BB468F7C72FD1FF2/BfycW4hQb3wNP4YsiJW-1n6fjro.cer")
.expect("read issuer ca");
let issuer_ca = ResourceCertificate::decode_der(&issuer_ca_der).expect("decode issuer ca");
// Choose a validation_time that is safely inside:
// - manifest thisUpdate..nextUpdate
// - issuer CA validity
// - CRL thisUpdate..nextUpdate
let manifest_der = std::fs::read(&manifest_path).expect("read manifest");
let manifest = ManifestObject::decode_der(&manifest_der).expect("decode manifest");
let crl_der = std::fs::read(fixture_dir.join("05FC9C5B88506F7C0D3F862C8895BED67E9F8EBA.crl"))
.expect("read crl");
let crl = RpkixCrl::decode_der(&crl_der).expect("decode crl");
let mut t = manifest.manifest.this_update;
if issuer_ca.tbs.validity_not_before > t {
t = issuer_ca.tbs.validity_not_before;
}
if crl.this_update.utc > t {
t = crl.this_update.utc;
}
t += time::Duration::seconds(1);
let mut policy = Policy::default();
policy.sync_preference = SyncPreference::RsyncOnly;
let rsync_fetcher = LocalDirRsyncFetcher::new(fixture_dir);
let http_fetcher = NeverHttpFetcher;
let temp = tempfile::tempdir().expect("tempdir");
let store = RocksStore::open(temp.path()).expect("open rocksdb");
let expected_files = std::fs::read_dir(fixture_dir)
.expect("read fixture dir")
.filter_map(|e| e.ok())
.filter_map(|e| e.metadata().ok().map(|m| (e, m)))
.filter(|(_e, m)| m.is_file())
.count();
assert!(expected_files >= 3, "fixture dir seems incomplete");
let out = run_publication_point_once(
&store,
&policy,
None,
rsync_base_uri,
&manifest_rsync_uri,
&publication_point_rsync_uri,
&http_fetcher,
&rsync_fetcher,
&issuer_ca_der,
None,
issuer_ca.tbs.extensions.ip_resources.as_ref(),
issuer_ca.tbs.extensions.as_resources.as_ref(),
t,
)
.expect("run publication point once");
assert!(fetch_cache_pp_exists(&store, &manifest_rsync_uri).expect("exists check"));
assert_eq!(out.repo_sync.objects_written, expected_files);
assert!(
out.objects.vrps.iter().any(|v| v.asn == 4538),
"expected VRPs for AS4538"
);
}