diff --git a/crates/scanner/tests/heal_generation_observation.rs b/crates/scanner/tests/heal_generation_observation/mod.rs similarity index 84% rename from crates/scanner/tests/heal_generation_observation.rs rename to crates/scanner/tests/heal_generation_observation/mod.rs index 0c61fb27d..a7b361bad 100644 --- a/crates/scanner/tests/heal_generation_observation.rs +++ b/crates/scanner/tests/heal_generation_observation/mod.rs @@ -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>>); @@ -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"; diff --git a/crates/scanner/tests/lifecycle_integration_test.rs b/crates/scanner/tests/lifecycle_integration_test.rs index 713f00edc..eb4de5770 100644 --- a/crates/scanner/tests/lifecycle_integration_test.rs +++ b/crates/scanner/tests/lifecycle_integration_test.rs @@ -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::{ diff --git a/crates/scanner/tests/storage_api/mod.rs b/crates/scanner/tests/storage_api/mod.rs index 1bf2ffaf3..7aa7d9e76 100644 --- a/crates/scanner/tests/storage_api/mod.rs +++ b/crates/scanner/tests/storage_api/mod.rs @@ -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, }; }