mirror of
https://github.com/rustfs/rustfs.git
synced 2026-08-19 11:06:17 +00:00
test(interop): add real MinIO read and migration parity tests (#4377)
test(interop): real-MinIO read + migration parity, Phase 1/2 (backlog#580) Capture authentic on-disk fixtures from MinIO RELEASE.2025-07-23 (a bucket with versioning, object-lock, lifecycle, tagging, quota, a public policy, SSE-S3 encryption, a webhook notification target, and a replication rule, plus inline / versioned / multipart objects and a delete marker) and prove RustFS reads and migrates them losslessly: - filemeta parses_real_minio_object_xlmeta: small inline, two-object-version + delete marker, and multipart object xl.meta parse to the expected FileInfo. - ecstore parses_real_minio_bucket_metadata_blob_without_loss: the MinIO .metadata.bin msgpack decodes via the PascalCase field names and parse_all_configs loads all ten config types present (policy, lifecycle incl. <ExpiryUpdatedAt>, object-lock, versioning, tagging, quota, notification, encryption/SSE-S3, replication incl. DeleteMarkerReplication / ExistingObjectReplication) without loss. - ecstore reads_minio_inline_bucket_metadata_via_bitrot: MinIO inlines an object body as [HighwayHash256 32B][body]; RustFS's BitrotReader with HighwayHash256S verifies and yields the exact blob (the "inline_data 前缀不同" is that prefix). - ecstore migrates_real_minio_bucket_metadata_end_to_end: on a throwaway 4-drive local ECStore, a real MinIO .metadata.bin seeded under .minio.sys is migrated into .rustfs.sys byte-identically for every config, exercising the Phase 2 source adapter (MIGRATING_META_BUCKET = ".minio.sys") through the object layer. All four run as ordinary crate tests (nextest CI). Phase 4 (MinIO re-reading a RustFS drive) is documented as out of scope for one-way migration. Refs rustfs/backlog#580
This commit is contained in:
@@ -920,6 +920,52 @@ mod test {
|
||||
use proptest::collection::vec;
|
||||
use proptest::prelude::*;
|
||||
|
||||
/// backlog#580: RustFS parses real MinIO-written object xl.meta (inline,
|
||||
/// versioned, and multipart) into equivalent `FileInfo`. Object metadata is
|
||||
/// the strong part of MinIO interop; this pins it against real fixtures.
|
||||
#[test]
|
||||
fn parses_real_minio_object_xlmeta() {
|
||||
// Small inlined object.
|
||||
let small = create_minio_small_object_xlmeta().expect("load small fixture");
|
||||
let (major, _minor, _hdr, meta_ver) = FileMeta::read_format_versions(&small).unwrap();
|
||||
assert_eq!(major, 1);
|
||||
assert_eq!(meta_ver, FileMeta::load(&small).unwrap().meta_ver);
|
||||
let fm = FileMeta::load(&small).expect("parse small MinIO xl.meta");
|
||||
assert_eq!(fm.versions.len(), 1);
|
||||
let fi = fm
|
||||
.into_fileinfo("interop", "small.txt", "", false, false, true)
|
||||
.expect("small fileinfo");
|
||||
assert_eq!(fi.size, 19, "small.txt size");
|
||||
assert_eq!(fi.num_versions, 1);
|
||||
assert!(fi.is_latest);
|
||||
|
||||
// Versioned object: two object versions plus a delete marker (latest).
|
||||
let versioned = create_minio_versioned_object_xlmeta().expect("load versioned fixture");
|
||||
let fm = FileMeta::load(&versioned).expect("parse versioned MinIO xl.meta");
|
||||
assert_eq!(fm.versions.len(), 3, "two object versions + one delete marker");
|
||||
let delete_markers = fm
|
||||
.versions
|
||||
.iter()
|
||||
.filter(|v| v.header.version_type == VersionType::Delete)
|
||||
.count();
|
||||
assert_eq!(delete_markers, 1, "delete marker parsed from MinIO xl.meta");
|
||||
let fi = fm
|
||||
.into_fileinfo("interop", "versioned.txt", "", false, false, true)
|
||||
.expect("versioned fileinfo");
|
||||
assert_eq!(fi.num_versions, 3);
|
||||
assert!(fi.version_id.is_some(), "versioned object carries a version id");
|
||||
|
||||
// Larger object stored as an erasure-coded part (not inlined).
|
||||
let large = create_minio_large_object_xlmeta().expect("load large fixture");
|
||||
let fm = FileMeta::load(&large).expect("parse large MinIO xl.meta");
|
||||
assert_eq!(fm.versions.len(), 1);
|
||||
let fi = fm
|
||||
.into_fileinfo("interop", "large.bin", "", false, false, true)
|
||||
.expect("large fileinfo");
|
||||
assert_eq!(fi.size, 300_000, "large.bin size");
|
||||
assert!(!fi.parts.is_empty(), "multipart/part layout present");
|
||||
}
|
||||
|
||||
/// Wraps a raw meta block in a valid XL2 container (header, bin32 length
|
||||
/// prefix, and CRC trailer) so decode tests exercise the meta parsing
|
||||
/// itself rather than the envelope checks.
|
||||
|
||||
@@ -151,6 +151,26 @@ pub fn create_issue_2434_legacy_meta_v2_pool_xlmeta() -> Result<Vec<u8>> {
|
||||
decode_hex_fixture(include_str!("../tests/fixtures/issue_2434_legacy_meta_v2_pool.hex"))
|
||||
}
|
||||
|
||||
/// Real MinIO-written xl.meta for a small inlined object (`small.txt`, 19 bytes),
|
||||
/// captured from MinIO `RELEASE.2025-07-23` — see `tests/fixtures/minio/README.md`
|
||||
/// (backlog#580).
|
||||
pub fn create_minio_small_object_xlmeta() -> Result<Vec<u8>> {
|
||||
decode_hex_fixture(include_str!("../tests/fixtures/minio/object_small_txt.xlmeta.hex"))
|
||||
}
|
||||
|
||||
/// Real MinIO-written xl.meta for a versioned object (`versioned.txt`, two
|
||||
/// versions) — see `tests/fixtures/minio/README.md` (backlog#580).
|
||||
pub fn create_minio_versioned_object_xlmeta() -> Result<Vec<u8>> {
|
||||
decode_hex_fixture(include_str!("../tests/fixtures/minio/object_versioned_txt.xlmeta.hex"))
|
||||
}
|
||||
|
||||
/// Real MinIO-written xl.meta for a larger, non-inlined object (`large.bin`,
|
||||
/// 300 KiB, stored as `part.1`) — see `tests/fixtures/minio/README.md`
|
||||
/// (backlog#580).
|
||||
pub fn create_minio_large_object_xlmeta() -> Result<Vec<u8>> {
|
||||
decode_hex_fixture(include_str!("../tests/fixtures/minio/object_large_bin.xlmeta.hex"))
|
||||
}
|
||||
|
||||
fn write_legacy_time(wr: &mut Vec<u8>, ts: OffsetDateTime) {
|
||||
wr.push(MSGPACK_EXT8);
|
||||
wr.push(12);
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
584c322001000300c6000001a4030301c42697c410727d23b40d2944e98e80d34405582863d318c00d6f34711ea0c404ad77932901020001c5017683a45479706501a556324f626ade0011a24944c410727d23b40d2944e98e80d34405582863a444446972c41059f847a8f7844db9b905a8352a9906bfa64563416c676f01a345634d01a345634e00a745634253697a65d200100000a74563496e64657801a64563446973749101a84353756d416c676f01a8506172744e756d739101a9506172744554616773c0a95061727453697a657391d2000493e0aa506172744153697a657391d2000493e0a453697a65d2000493e0a54d54696d65d318c00d6f34711ea0a74d65746153797382bc582d4d696e696f2d496e7465726e616c2d61637475616c2d73697a65c406333030303030b4782d6d696e696f2d696e7465726e616c2d637263c40bd001bbcd55bc019325344da74d65746155737282a465746167d92231326365653861623034393337646333333236666364326163633538626265352d31ac636f6e74656e742d74797065b86170706c69636174696f6e2f6f637465742d73747265616da176ce6881059aceb9aa266a
|
||||
@@ -0,0 +1 @@
|
||||
584c322001000300c600000186030301c42697c410746dde29b59243efac7e37d408079143d318c00d6f26446968c4047761ed8301020001c5015883a45479706501a556324f626ade0011a24944c410746dde29b59243efac7e37d408079143a444446972c41019286b7785854468b7e9a8efddf329d7a64563416c676f01a345634d01a345634e00a745634253697a65d200100000a74563496e64657801a64563446973749101a84353756d416c676f01a8506172744e756d739101a9506172744554616773c0a95061727453697a65739113aa506172744153697a65739113a453697a6513a54d54696d65d318c00d6f26446968a74d65746153797382bc582d4d696e696f2d496e7465726e616c2d61637475616c2d73697a65c4023139b4782d6d696e696f2d696e7465726e616c2d637263c40bd0012cd2c3a001f50b8e4ba74d65746155737282ac636f6e74656e742d74797065aa746578742f706c61696ea465746167d92261396238633039663133663333663537306430326264346462316662356439372d31a176ce6881059ace755b0e49
|
||||
@@ -0,0 +1 @@
|
||||
584c322001000300c600000375030303c42697c4106178c538372e4d93a122e55fc1bed128d318c00d6f3a44dd58c40439c29d5902000000c44383a45479706502a644656c4f626a83a24944c4106178c538372e4d93a122e55fc1bed128a54d54696d65d318c00d6f3a44dd58a74d65746153797380a176ce6881059ac42697c410065f0d6b0c1b4f94bfe1e98e8235fcf1d318c00d6f2fe16138c4049e93c2e701020001c5015883a45479706501a556324f626ade0011a24944c410065f0d6b0c1b4f94bfe1e98e8235fcf1a444446972c4108b76b5d6063245b6a4da67a01789d62ca64563416c676f01a345634d01a345634e00a745634253697a65d200100000a74563496e64657801a64563446973749101a84353756d416c676f01a8506172744e756d739101a9506172744554616773c0a95061727453697a6573910caa506172744153697a6573910ca453697a650ca54d54696d65d318c00d6f2fe16138a74d65746153797382bc582d4d696e696f2d496e7465726e616c2d61637475616c2d73697a65c4023132b4782d6d696e696f2d696e7465726e616c2d637263c40bd0014d39f0a401ff13e583a74d65746155737282ac636f6e74656e742d74797065aa746578742f706c61696ea465746167d92263363239643133613630313832303136356237333638373331313430613738632d31a176ce6881059ac42697c410b12dfda0210b405b89b1eaafd1964008d318c00d6f2b5d4848c404fc20d11a01020001c5015783a45479706501a556324f626ade0011a24944c410b12dfda0210b405b89b1eaafd1964008a444446972c41001dd843548214e4abbdfc472b35ec475a64563416c676f01a345634d01a345634e00a745634253697a65d200100000a74563496e64657801a64563446973749101a84353756d416c676f01a8506172744e756d739101a9506172744554616773c0a95061727453697a65739102aa506172744153697a65739102a453697a6502a54d54696d65d318c00d6f2b5d4848a74d65746153797382bc582d4d696e696f2d496e7465726e616c2d61637475616c2d73697a65c40132b4782d6d696e696f2d696e7465726e616c2d637263c40bd001e1792ab801e57f38d5a74d65746155737282ac636f6e74656e742d74797065aa746578742f706c61696ea465746167d92239306262653039353930353265626361656630623038323733666235313063372d31a176ce6881059ace638dab49
|
||||
Reference in New Issue
Block a user