use std::path::Path; use rpki::storage::{ PackTime, RawByHashEntry, RepositoryViewEntry, RepositoryViewState, RocksStore, RrdpSourceRecord, RrdpSourceSyncState, }; use sha2::Digest; fn put_current_object(store: &RocksStore, rsync_uri: &str, bytes: &[u8], object_type: &str) { let sha256_hex = hex::encode(sha2::Sha256::digest(bytes)); let mut raw = RawByHashEntry::from_bytes(sha256_hex.clone(), bytes.to_vec()); raw.origin_uris.push(rsync_uri.to_string()); raw.object_type = Some(object_type.to_string()); raw.encoding = Some("der".to_string()); store.put_raw_by_hash_entry(&raw).expect("put raw_by_hash"); store .put_repository_view_entry(&RepositoryViewEntry { rsync_uri: rsync_uri.to_string(), current_hash: Some(sha256_hex), repository_source: Some("https://example.invalid/notification.xml".to_string()), object_type: Some(object_type.to_string()), state: RepositoryViewState::Present, }) .expect("put repository view"); } #[test] fn storage_opens_and_creates_column_families() { let dir = tempfile::tempdir().expect("tempdir"); let _store = RocksStore::open(dir.path()).expect("open rocksdb"); } #[test] fn current_object_roundtrip_by_rsync_uri() { let dir = tempfile::tempdir().expect("tempdir"); let store = RocksStore::open(dir.path()).expect("open rocksdb"); let key = "rsync://example.invalid/repo/a.cer"; let value = b"hello"; put_current_object(&store, key, value, "cer"); let got = store .load_current_object_bytes_by_uri(key) .expect("get current object"); assert_eq!(got.as_deref(), Some(value.as_slice())); let current_hash = store .get_repository_view_entry(key) .expect("get repository view") .expect("view exists") .current_hash .expect("current hash"); store .delete_repository_view_entry(key) .expect("delete repository view"); store .delete_raw_by_hash_entry(¤t_hash) .expect("delete raw_by_hash"); let got = store .load_current_object_bytes_by_uri(key) .expect("get current object after delete"); assert!(got.is_none()); } #[test] fn rrdp_source_roundtrip_by_notification_uri() { let dir = tempfile::tempdir().expect("tempdir"); let store = RocksStore::open(dir.path()).expect("open rocksdb"); let notif = "https://example.invalid/rrdp/notification.xml"; let record = RrdpSourceRecord { notify_uri: notif.to_string(), last_session_id: Some("00000000-0000-0000-0000-000000000000".to_string()), last_serial: Some(1), first_seen_at: PackTime::from_utc_offset_datetime(time::OffsetDateTime::now_utc()), last_seen_at: PackTime::from_utc_offset_datetime(time::OffsetDateTime::now_utc()), last_sync_at: None, sync_state: RrdpSourceSyncState::SnapshotOnly, last_snapshot_uri: None, last_snapshot_hash: None, last_error: None, }; store.put_rrdp_source_record(&record).expect("put rrdp_source"); let got = store .get_rrdp_source_record(notif) .expect("get rrdp_source") .expect("rrdp_source present"); assert_eq!(got.last_serial, Some(1)); assert_eq!( got.last_session_id.as_deref(), Some("00000000-0000-0000-0000-000000000000") ); } #[test] fn store_is_reopenable() { let dir = tempfile::tempdir().expect("tempdir"); let path: &Path = dir.path(); let store = RocksStore::open(path).expect("open rocksdb"); put_current_object(&store, "rsync://example.invalid/repo/x", b"x", "bin"); drop(store); let store = RocksStore::open(path).expect("reopen rocksdb"); let got = store .load_current_object_bytes_by_uri("rsync://example.invalid/repo/x") .expect("get after reopen"); assert_eq!(got.as_deref(), Some(b"x".as_slice())); }