test(scanner): route heal integration through storage boundary

This commit is contained in:
overtrue
2026-10-28 01:19:45 +08:00
parent 5c515eec5d
commit 9dbff55f75
3 changed files with 46 additions and 12 deletions
@@ -14,7 +14,6 @@
//! One local process exercises the scanner, heal manager, and real ECStore.
use rustfs_ecstore::api::object::{ShardIntegrityWriteMode, WriteCommitGuard, WriteCompletion};
use rustfs_heal::{
HealChannelProcessor,
heal::{
@@ -30,7 +29,6 @@ use rustfs_heal_contracts::{
use rustfs_scanner::{
ScannerObjectOptions, ScannerPutObjReader, SizeSummary, scanner_folder::ScannerItem, scanner_heal_observation_status,
};
use rustfs_storage_api::{NamespaceLocking, ObjectIO, ObjectOperations};
use rustfs_test_utils::TestECStoreEnv;
use std::{
collections::HashMap,
@@ -39,6 +37,10 @@ use std::{
};
use time::OffsetDateTime;
use super::storage_api::lifecycle::{
NamespaceLocking, ObjectIO, ObjectOperations, ShardIntegrityWriteMode, WriteCommitGuard, WriteCompletion,
};
#[derive(Default)]
struct CounterRecorder(Mutex<HashMap<metrics::Key, Arc<AtomicU64>>>);
@@ -94,8 +96,37 @@ async fn put_protected(env: &TestECStoreEnv, bucket: &str, object: &str, fill: u
.expect("write protected object to the real erasure set");
}
#[tokio::test]
async fn overwritten_unversioned_generation_is_only_a_data_dir_observation() {
#[test]
#[serial_test::serial]
fn overwritten_unversioned_generation_is_only_a_data_dir_observation() {
const CHILD_ENV: &str = "RUSTFS_TEST_SCANNER_HEAL_GENERATION_CHILD";
const CHILD_STARTED: &str = "scanner-heal-generation-child-started";
if std::env::var_os(CHILD_ENV).is_none() {
let output = std::process::Command::new(std::env::current_exe().expect("test executable"))
.arg("--exact")
.arg("heal_generation_observation::overwritten_unversioned_generation_is_only_a_data_dir_observation")
.arg("--nocapture")
.env(CHILD_ENV, "1")
.output()
.expect("run scanner-heal test in an isolated process");
let stdout = String::from_utf8_lossy(&output.stdout);
assert!(
output.status.success() && stdout.contains(CHILD_STARTED),
"scanner-heal child failed or was not selected:\n{}\n{}",
stdout,
String::from_utf8_lossy(&output.stderr)
);
return;
}
println!("{CHILD_STARTED}");
tokio::runtime::Builder::new_current_thread()
.enable_all()
.build()
.expect("scanner-heal test runtime")
.block_on(run_overwritten_unversioned_generation_observation());
}
async fn run_overwritten_unversioned_generation_observation() {
let root = tempfile::tempdir().expect("local erasure-set fixture");
let env = TestECStoreEnv::builder().base_dir(root.path()).build().await;
let bucket = "scanner-generation";
@@ -37,6 +37,7 @@ use tokio_util::sync::CancellationToken;
use tracing::info;
use uuid::Uuid;
mod heal_generation_observation;
mod storage_api;
use storage_api::lifecycle::{
+10 -8
View File
@@ -32,6 +32,7 @@ pub(crate) use rustfs_ecstore::api::disk::{DiskOption, STORAGE_FORMAT_FILE, endp
pub(crate) use rustfs_ecstore::api::error::{Error as EcstoreError, is_err_object_not_found, is_err_version_not_found};
pub(crate) use rustfs_ecstore::api::layout::{EndpointServerPools, Endpoints, PoolEndpoints};
pub(crate) use rustfs_ecstore::api::object::test_util::DeleteAfterObjectLockSnapshotBarrier;
pub(crate) use rustfs_ecstore::api::object::{ShardIntegrityWriteMode, WriteCommitGuard, WriteCompletion};
pub(crate) use rustfs_ecstore::api::runtime::global_tier_config_mgr as get_global_tier_config_mgr;
pub(crate) use rustfs_ecstore::api::storage::{ECStore, init_local_disks};
// Shared lifecycle/tier test utilities (rustfs/backlog#1148 ilm-6). The mock
@@ -45,18 +46,19 @@ use rustfs_storage_api as storage_contracts;
pub(crate) mod lifecycle {
pub(crate) use super::storage_contracts::{
BucketOperations, BucketOptions, CompletePart, ListOperations, MakeBucketOptions, MultipartOperations, ObjectIO,
ObjectOperations,
BucketOperations, BucketOptions, CompletePart, ListOperations, MakeBucketOptions, MultipartOperations, NamespaceLocking,
ObjectIO, ObjectOperations,
};
pub(crate) use super::{
BUCKET_LIFECYCLE_CONFIG, BUCKET_VERSIONING_CONFIG, BucketVersioningSys, DeleteAfterObjectLockSnapshotBarrier, DiskOption,
ECStore, EcstoreError, Endpoint, EndpointServerPools, Endpoints, ExpiryState, IlmAction, LcEvent, LcEventSrc,
MockWarmBackend, PoolEndpoints, STORAGE_FORMAT_FILE, TRANSITION_PENDING, TransitionCleanupStoreBarrier,
TransitionOptions, assert_transition_meta_consistent, enqueue_transition_for_existing_objects,
expire_transitioned_object, free_version_count, get_bucket_metadata, get_global_tier_config_mgr, init_background_expiry,
init_bucket_metadata_sys, init_local_disks, is_err_object_not_found, is_err_version_not_found, new_disk,
path2_bucket_object_with_base_path, recover_transition_transaction_records, recover_transition_transaction_records_at,
register_mock_tier_util, update_bucket_metadata, wait_for_free_version_absence,
MockWarmBackend, PoolEndpoints, STORAGE_FORMAT_FILE, ShardIntegrityWriteMode, TRANSITION_PENDING,
TransitionCleanupStoreBarrier, TransitionOptions, WriteCommitGuard, WriteCompletion, assert_transition_meta_consistent,
enqueue_transition_for_existing_objects, expire_transitioned_object, free_version_count, get_bucket_metadata,
get_global_tier_config_mgr, init_background_expiry, init_bucket_metadata_sys, init_local_disks, is_err_object_not_found,
is_err_version_not_found, new_disk, path2_bucket_object_with_base_path, recover_transition_transaction_records,
recover_transition_transaction_records_at, register_mock_tier_util, update_bucket_metadata,
wait_for_free_version_absence,
};
}