From 7fb405526bad94274070bc384011b7648dd63808 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AE=89=E6=AD=A3=E8=B6=85?= Date: Sun, 29 Mar 2026 20:05:48 +0800 Subject: [PATCH] test(filemeta): cover legacy delete marker fallback (#2322) --- crates/filemeta/src/filemeta/version.rs | 73 ++++++++++++++++++++++++- 1 file changed, 72 insertions(+), 1 deletion(-) diff --git a/crates/filemeta/src/filemeta/version.rs b/crates/filemeta/src/filemeta/version.rs index 11e716f14..359cbff54 100644 --- a/crates/filemeta/src/filemeta/version.rs +++ b/crates/filemeta/src/filemeta/version.rs @@ -540,7 +540,7 @@ impl TryFrom<&[u8]> for FileMetaVersion { fn try_from(value: &[u8]) -> std::result::Result { let mut ver = FileMetaVersion::default(); - if ver.unmarshal_msg(value).is_ok() { + if ver.unmarshal_msg(value).is_ok() && ver.valid() { ver.uses_legacy_checksum = false; return Ok(ver); } @@ -2715,6 +2715,28 @@ pub async fn read_xl_meta_no_data(reader: &mut R, size: us #[cfg(test)] mod tests { use super::*; + use serde::Serialize; + + #[derive(Serialize)] + enum LegacyDeleteVersionTypeFixture { + #[serde(rename = "DeleteMarker")] + DeleteMarker, + } + + #[derive(Serialize)] + struct LegacyDeleteMarkerFixture { + version_id: Vec, + mod_time: Option, + meta_sys: HashMap>, + } + + #[derive(Serialize)] + struct LegacyDeleteVersionFixture { + version_type: LegacyDeleteVersionTypeFixture, + object: Option<()>, + delete_marker: Option, + write_version: u64, + } fn sample_version_id() -> Uuid { Uuid::parse_str("01234567-89ab-cdef-0123-456789abcdef").unwrap() @@ -2912,4 +2934,53 @@ mod tests { assert_eq!(fi.erasure.parity_blocks, 2); assert_eq!(fi.metadata.get("content-type").map(String::as_str), Some("text/plain")); } + + #[test] + fn legacy_meta_v2_delete_marker_decodes_into_delete_fileinfo() { + let payload = LegacyDeleteVersionFixture { + version_type: LegacyDeleteVersionTypeFixture::DeleteMarker, + object: None, + delete_marker: Some(LegacyDeleteMarkerFixture { + version_id: sample_version_id().as_bytes().to_vec(), + mod_time: Some(sample_mod_time()), + meta_sys: HashMap::from([("x-rustfs-test".to_string(), b"gone".to_vec())]), + }), + write_version: 9, + }; + let encoded = rmp_serde::to_vec_named(&payload).unwrap(); + + let decoded = FileMetaVersion::try_from(encoded.as_slice()).unwrap(); + + assert_eq!(decoded.version_type, VersionType::Delete); + assert!(decoded.object.is_none()); + assert!(decoded.delete_marker.is_some()); + assert!(decoded.uses_legacy_checksum); + + let fi = decoded.into_fileinfo("bucket", "gone.txt", true); + assert!(fi.deleted); + assert_eq!(fi.volume, "bucket"); + assert_eq!(fi.name, "gone.txt"); + assert_eq!(fi.version_id, Some(sample_version_id())); + assert_eq!(fi.mod_time, Some(sample_mod_time())); + assert_eq!(fi.metadata.get("x-rustfs-test").map(String::as_str), Some("gone")); + assert!(fi.uses_legacy_checksum); + } + + #[test] + fn legacy_meta_v2_delete_marker_rejects_invalid_uuid_bytes() { + let payload = LegacyDeleteVersionFixture { + version_type: LegacyDeleteVersionTypeFixture::DeleteMarker, + object: None, + delete_marker: Some(LegacyDeleteMarkerFixture { + version_id: vec![7; 15], + mod_time: Some(sample_mod_time()), + meta_sys: HashMap::new(), + }), + write_version: 10, + }; + let encoded = rmp_serde::to_vec_named(&payload).unwrap(); + + let err = FileMetaVersion::try_from(encoded.as_slice()).expect_err("invalid legacy delete marker UUID must fail"); + assert!(err.to_string().contains("legacy version_id must be 16 bytes")); + } }