diff --git a/Cargo.lock b/Cargo.lock index cc185ac41..cdbac3713 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2031,6 +2031,17 @@ dependencies = [ "crossbeam-utils", ] +[[package]] +name = "console" +version = "0.16.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d64e8af5551369d19cf50138de61f1c42074ab970f74e99be916646777f8fc87" +dependencies = [ + "encode_unicode", + "libc", + "windows-sys 0.61.2", +] + [[package]] name = "const-oid" version = "0.9.6" @@ -3835,6 +3846,12 @@ dependencies = [ "zeroize", ] +[[package]] +name = "encode_unicode" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0" + [[package]] name = "encoding_rs" version = "0.8.35" @@ -5288,6 +5305,19 @@ dependencies = [ "hybrid-array", ] +[[package]] +name = "insta" +version = "1.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86f0f8fee8c926415c58d6ae43a08523a26faccb2323f5e6b644fe7dd4ef6b82" +dependencies = [ + "console", + "once_cell", + "serde", + "similar", + "tempfile", +] + [[package]] name = "internal-russh-num-bigint" version = "0.5.0" @@ -9282,6 +9312,7 @@ dependencies = [ "hyper", "hyper-rustls", "hyper-util", + "insta", "lazy_static", "libc", "md-5 0.11.0", @@ -10910,6 +10941,12 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e" +[[package]] +name = "similar" +version = "2.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbbb5d9659141646ae647b42fe094daf6c6192d1620870b449d9557f748b2daa" + [[package]] name = "simple_asn1" version = "0.6.4" diff --git a/Cargo.toml b/Cargo.toml index 0b66e0235..a12feb58e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -333,6 +333,8 @@ mimalloc = "0.1" tikv-jemallocator = { version = "0.6", features = ["profiling", "stats", "unprefixed_malloc_on_supported_platforms", "background_threads"] } # Used to control and obtain statistics for jemalloc at runtime tikv-jemalloc-ctl = { version = "0.6", features = ["use_std", "stats", "profiling"] } +# Snapshot testing for output format regression detection +insta = { version = "1.41", features = ["yaml", "json"] } # Used to generate pprof-compatible memory profiling data and support symbolization and flame graphs jemalloc_pprof = { version = "0.8.2", features = ["symbolize", "flamegraph"] } # Used to generate CPU performance analysis data and flame diagrams diff --git a/crates/ecstore/Cargo.toml b/crates/ecstore/Cargo.toml index a7e418542..926d18946 100644 --- a/crates/ecstore/Cargo.toml +++ b/crates/ecstore/Cargo.toml @@ -145,6 +145,7 @@ serial_test = { workspace = true } opentelemetry_sdk = { workspace = true } proptest = "1" rcgen.workspace = true +insta = { workspace = true } [build-dependencies] shadow-rs = { workspace = true, features = ["build", "metadata"] } diff --git a/crates/ecstore/src/error/mod.rs b/crates/ecstore/src/error/mod.rs index 0b1e2c1d9..ade95c1fd 100644 --- a/crates/ecstore/src/error/mod.rs +++ b/crates/ecstore/src/error/mod.rs @@ -1448,4 +1448,34 @@ mod tests { assert_eq!(original_error, recovered_error); } } + + #[test] + fn test_storage_error_display_snapshot() { + // Snapshot test to detect unexpected changes in error display format + let errors = vec![ + StorageError::BucketNotFound("test-bucket".to_string()), + StorageError::ObjectNotFound("bucket".to_string(), "object".to_string()), + StorageError::VersionNotFound("bucket".to_string(), "object".to_string(), "v1".to_string()), + StorageError::InvalidUploadID("bucket".to_string(), "object".to_string(), "upload123".to_string()), + StorageError::DiskFull, + StorageError::FaultyDisk, + StorageError::FileNotFound, + StorageError::VolumeNotFound, + StorageError::ErasureReadQuorum, + StorageError::ErasureWriteQuorum, + StorageError::DecommissionAlreadyRunning, + StorageError::RebalanceAlreadyRunning, + StorageError::OperationCanceled, + StorageError::NamespaceLockQuorumUnavailable { + mode: "write", + bucket: "bucket".into(), + object: "object".into(), + required: 3, + achieved: 2, + }, + ]; + + let error_messages: Vec = errors.iter().map(|e| e.to_string()).collect(); + insta::assert_yaml_snapshot!("storage_error_display", error_messages); + } } diff --git a/crates/ecstore/src/error/snapshots/rustfs_ecstore__error__tests__storage_error_display.snap b/crates/ecstore/src/error/snapshots/rustfs_ecstore__error__tests__storage_error_display.snap new file mode 100644 index 000000000..08ece6610 --- /dev/null +++ b/crates/ecstore/src/error/snapshots/rustfs_ecstore__error__tests__storage_error_display.snap @@ -0,0 +1,18 @@ +--- +source: crates/ecstore/src/error/mod.rs +expression: error_messages +--- +- "Bucket not found: test-bucket" +- "Object not found: bucket/object" +- "Version not found: bucket/object-v1" +- "Invalid upload id: bucket/object-upload123" +- Disk full +- Faulty disk +- File not found +- Volume not found +- erasure read quorum +- erasure write quorum +- Decommission already running +- Rebalance already running +- Operation canceled +- "Namespace lock quorum unavailable for write lock on bucket/object: required 3, achieved 2"