diff --git a/.config/nextest.toml b/.config/nextest.toml index 8eb68deaf..b8ed8e626 100644 --- a/.config/nextest.toml +++ b/.config/nextest.toml @@ -89,6 +89,29 @@ test-group = 'ecstore-serial-flaky' filter = 'package(rustfs-ecstore) & test(/^set_disk::ops::multipart::tests::crash_consistency::/)' test-group = 'ecstore-serial-flaky' +# Serialize the heal result-report tests. Every test in the module builds a +# real-disk (TempDir-backed) hermetic erasure set and drives MiB-scale writes +# plus deep-scan heal — the same load-sensitive cross-disk IO shape as the +# crash_consistency scenarios above. Under a heavily parallel run a single +# disk's IO can fail while write quorum still holds, which flips per-disk +# readback and aggregate-outcome assertions nondeterministically (different +# tests each round; all pass standalone). Preventive serialization only, no +# retries. The matching ci-profile override is after [profile.ci]. +[[profile.default.overrides]] +filter = 'package(rustfs-ecstore) & test(/^set_disk::ops::heal::heal_result_report_tests::/)' +test-group = 'ecstore-serial-flaky' + +# Serialize the metadata-cache generation-retirement pair. Both carry +# #[serial(metadata_cache_invalidation_probe)] — a no-op across nextest's +# process boundary — and assert get_object_metadata_cache generation +# semantics on a 4-disk hermetic set, the same load-sensitive shape that +# forced the transition matrix tests into this group. Preventive +# serialization only, no retries. The matching ci-profile override is after +# [profile.ci]. +[[profile.default.overrides]] +filter = 'package(rustfs-ecstore) & test(retires_cached_snapshot)' +test-group = 'ecstore-serial-flaky' + # The production-handler relocation regression builds an isolated 8-disk, # 2-pool store and commits a 72 MiB multipart object. Keep that cross-disk IO # from overlapping the ecstore commit fixtures above. @@ -250,6 +273,20 @@ test-group = 'e2e-reliability' filter = 'package(rustfs-ecstore) & test(/^set_disk::ops::multipart::tests::crash_consistency::/)' test-group = 'ecstore-serial-flaky' +# Serialize the heal result-report tests under the ci profile too (see the +# matching default-profile override near the top). Not a quarantine: no +# retries, just serialized real-disk heal IO. +[[profile.ci.overrides]] +filter = 'package(rustfs-ecstore) & test(/^set_disk::ops::heal::heal_result_report_tests::/)' +test-group = 'ecstore-serial-flaky' + +# Serialize the metadata-cache generation-retirement pair under the ci +# profile too (see the matching default-profile override near the top). Not a +# quarantine: no retries. +[[profile.ci.overrides]] +filter = 'package(rustfs-ecstore) & test(retires_cached_snapshot)' +test-group = 'ecstore-serial-flaky' + # Match the default-profile embedded test isolation without quarantining or # retrying failures in CI. [[profile.ci.overrides]] diff --git a/crates/ecstore/src/core/pools.rs b/crates/ecstore/src/core/pools.rs index e8f257433..dbafa91f1 100644 --- a/crates/ecstore/src/core/pools.rs +++ b/crates/ecstore/src/core/pools.rs @@ -7420,6 +7420,9 @@ type DecommissionCapacityInfoOverrides = #[cfg(test)] static DECOMMISSION_CAPACITY_INFO_OVERRIDES: std::sync::OnceLock = std::sync::OnceLock::new(); +/// Queues capacity snapshots consumed in order by `get_decommission_all_pool_capacity_infos`; +/// the final snapshot is retained and replayed for every subsequent sample, so tests never +/// fall back to the host's real disk statistics once an override is installed. #[cfg(test)] pub(crate) fn set_decommission_capacity_info_overrides_for_test( store_id: uuid::Uuid, @@ -7438,11 +7441,15 @@ fn take_decommission_capacity_info_override_for_test(store_id: uuid::Uuid) -> Op .get_or_init(|| std::sync::Mutex::new(HashMap::new())) .lock() .expect("decommission capacity info override should not be poisoned"); - let snapshot = overrides.get_mut(&store_id)?.pop_front(); - if overrides.get(&store_id).is_some_and(std::collections::VecDeque::is_empty) { - overrides.remove(&store_id); + let queue = overrides.get_mut(&store_id)?; + if queue.len() > 1 { + queue.pop_front() + } else { + // The final snapshot is replayed forever: extra sampling points added to + // the decommission paths must keep observing injected capacity instead of + // silently falling back to the host's real statfs numbers (see #6989). + queue.front().cloned() } - snapshot } #[cfg(test)]