use rpki::storage::{FetchCachePpPack, PackFile, PackTime}; fn base_pack() -> FetchCachePpPack { let this_update = PackTime::from_utc_offset_datetime(time::OffsetDateTime::from_unix_timestamp(0).unwrap()); let next_update = PackTime::from_utc_offset_datetime( time::OffsetDateTime::from_unix_timestamp(3600).unwrap(), ); let verified_at = PackTime::from_utc_offset_datetime(time::OffsetDateTime::from_unix_timestamp(10).unwrap()); let file = PackFile::from_bytes_compute_sha256("rsync://example.net/repo/obj.cer", b"x".to_vec()); FetchCachePpPack { format_version: FetchCachePpPack::FORMAT_VERSION_V1, manifest_rsync_uri: "rsync://example.net/repo/manifest.mft".to_string(), publication_point_rsync_uri: "rsync://example.net/repo/".to_string(), manifest_number_be: vec![1], this_update, next_update, verified_at, manifest_bytes: b"manifest".to_vec(), files: vec![file], } } #[test] fn pack_rejects_unsupported_format_version() { let mut pack = base_pack(); pack.format_version = 999; let bytes = pack.encode().expect("encode"); assert!( FetchCachePpPack::decode(&bytes) .unwrap_err() .to_string() .contains("unsupported pack format_version") ); } #[test] fn pack_rejects_missing_manifest_rsync_uri() { let mut pack = base_pack(); pack.manifest_rsync_uri.clear(); let bytes = pack.encode().expect("encode"); assert!(FetchCachePpPack::decode(&bytes).is_err()); } #[test] fn pack_rejects_missing_publication_point_rsync_uri() { let mut pack = base_pack(); pack.publication_point_rsync_uri.clear(); let bytes = pack.encode().expect("encode"); assert!(FetchCachePpPack::decode(&bytes).is_err()); } #[test] fn pack_rejects_missing_manifest_number() { let mut pack = base_pack(); pack.manifest_number_be.clear(); let bytes = pack.encode().expect("encode"); let err = FetchCachePpPack::decode(&bytes).unwrap_err(); assert!(err.to_string().contains("missing required field")); } #[test] fn pack_rejects_manifest_number_too_long() { let mut pack = base_pack(); pack.manifest_number_be = vec![1u8; 21]; let bytes = pack.encode().expect("encode"); let err = FetchCachePpPack::decode(&bytes).unwrap_err(); assert!(err.to_string().contains("at most 20 octets")); } #[test] fn pack_rejects_manifest_number_with_leading_zeros() { let mut pack = base_pack(); pack.manifest_number_be = vec![0u8, 1u8]; let bytes = pack.encode().expect("encode"); let err = FetchCachePpPack::decode(&bytes).unwrap_err(); assert!(err.to_string().contains("leading zeros")); } #[test] fn pack_rejects_invalid_time_fields() { let mut pack = base_pack(); pack.this_update = PackTime { rfc3339_utc: "not-a-time".to_string(), }; let bytes = pack.encode().expect("encode"); assert!(FetchCachePpPack::decode(&bytes).is_err()); } #[test] fn pack_rejects_empty_file_bytes() { let mut pack = base_pack(); let mut sha = [0u8; 32]; sha[0] = 1; pack.files = vec![PackFile::new( "rsync://example.net/repo/empty.cer", Vec::new(), sha, )]; let bytes = pack.encode().expect("encode"); assert!(FetchCachePpPack::decode(&bytes).is_err()); } #[test] fn pack_rejects_file_hash_mismatch() { let mut pack = base_pack(); pack.files = vec![PackFile::new( "rsync://example.net/repo/bad.cer", b"abc".to_vec(), [0u8; 32], )]; let bytes = pack.encode().expect("encode"); let err = FetchCachePpPack::decode(&bytes).unwrap_err(); assert!(err.to_string().contains("file hash mismatch")); } #[test] fn pack_rejects_missing_file_rsync_uri() { let mut pack = base_pack(); let file = PackFile::from_bytes_compute_sha256("", b"x".to_vec()); pack.files = vec![file]; let bytes = pack.encode().expect("encode"); let err = FetchCachePpPack::decode(&bytes).unwrap_err(); assert!(err.to_string().contains("missing required field")); }