test(ecstore): guard replication facade boundary (#4035)

This commit is contained in:
Zhengchao An
2026-06-29 10:32:09 +08:00
committed by GitHub
parent 319497446b
commit 801838fdbd
4 changed files with 80 additions and 0 deletions
@@ -47,3 +47,7 @@ and lifecycle/heal scheduling paths.
Start with `ReplicationRuntime` or `ReplicationEventSink`. Both can be added as Start with `ReplicationRuntime` or `ReplicationEventSink`. Both can be added as
narrow internal contracts while keeping current queue, MRF, resync, and target narrow internal contracts while keeping current queue, MRF, resync, and target
behavior unchanged. Do not start with a crate move. behavior unchanged. Do not start with a crate move.
Current compatibility guard: `crates/ecstore/tests/replication_facade_compat_test.rs`
keeps the ECStore replication facade types covered while architecture rules
keep direct imports behind local `storage_api` boundaries.
@@ -0,0 +1,56 @@
// Copyright 2024 RustFS Team
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
mod storage_api;
use s3s::dto::ReplicationConfiguration;
use storage_api::replication_compat::{
BucketStats, DeletedObjectReplicationInfo, DynReplicationPool, ObjectOpts, ReplicationConfigurationExt, ReplicationStats,
ResyncStatusType,
};
fn type_name<T>() -> &'static str {
std::any::type_name::<T>()
}
fn type_name_unsized<T: ?Sized>() -> &'static str {
std::any::type_name::<T>()
}
fn assert_replication_config_ext<T: ReplicationConfigurationExt>() {}
#[test]
fn replication_facade_exports_config_extension_contract() {
assert_replication_config_ext::<ReplicationConfiguration>();
}
#[test]
fn replication_facade_exports_runtime_and_dto_types() {
assert_eq!(ResyncStatusType::default(), ResyncStatusType::NoResync);
assert!(!ResyncStatusType::default().is_valid());
let object_opts = ObjectOpts::default();
assert!(object_opts.name.is_empty());
let deleted = DeletedObjectReplicationInfo::default();
assert!(deleted.bucket.is_empty());
let _stats = ReplicationStats::new();
let _bucket_stats = BucketStats::default();
assert!(type_name::<ReplicationStats>().contains("ReplicationStats"));
assert!(type_name::<BucketStats>().contains("BucketStats"));
assert!(type_name::<DeletedObjectReplicationInfo>().contains("DeletedObjectReplicationInfo"));
assert!(type_name_unsized::<DynReplicationPool>().contains("ReplicationPoolTrait"));
}
+7
View File
@@ -20,6 +20,13 @@ pub(crate) mod contract_compat {
pub(crate) use super::{DiskStore, ECStore, Error, GetObjectReader, ObjectInfo, ObjectOptions, PutObjReader, SetDisks}; pub(crate) use super::{DiskStore, ECStore, Error, GetObjectReader, ObjectInfo, ObjectOptions, PutObjReader, SetDisks};
} }
pub(crate) mod replication_compat {
pub(crate) use rustfs_ecstore::api::bucket::replication::{
BucketStats, DeletedObjectReplicationInfo, DynReplicationPool, ObjectOpts, ReplicationConfigurationExt, ReplicationStats,
ResyncStatusType,
};
}
pub(crate) mod legacy_bitrot_read { pub(crate) mod legacy_bitrot_read {
pub(crate) use super::{DiskOption, Endpoint, STORAGE_FORMAT_FILE, create_bitrot_reader, new_disk}; pub(crate) use super::{DiskOption, Endpoint, STORAGE_FORMAT_FILE, create_bitrot_reader, new_disk};
} }
@@ -181,6 +181,7 @@ RUSTFS_APP_ADMIN_STORAGE_HELPER_ROOT_REEXPORT_HITS_FILE="${TMP_DIR}/rustfs_app_a
EXTERNAL_TEST_ECSTORE_COMPAT_BYPASS_HITS_FILE="${TMP_DIR}/external_test_ecstore_compat_bypass_hits.txt" EXTERNAL_TEST_ECSTORE_COMPAT_BYPASS_HITS_FILE="${TMP_DIR}/external_test_ecstore_compat_bypass_hits.txt"
FUZZ_ECSTORE_COMPAT_BYPASS_HITS_FILE="${TMP_DIR}/fuzz_ecstore_compat_bypass_hits.txt" FUZZ_ECSTORE_COMPAT_BYPASS_HITS_FILE="${TMP_DIR}/fuzz_ecstore_compat_bypass_hits.txt"
EXTERNAL_ECSTORE_API_BOUNDARY_HITS_FILE="${TMP_DIR}/external_ecstore_api_boundary_hits.txt" EXTERNAL_ECSTORE_API_BOUNDARY_HITS_FILE="${TMP_DIR}/external_ecstore_api_boundary_hits.txt"
REPLICATION_FACADE_BYPASS_HITS_FILE="${TMP_DIR}/replication_facade_bypass_hits.txt"
LEGACY_ECSTORE_CONFIG_MODEL_HITS_FILE="${TMP_DIR}/legacy_ecstore_config_model_hits.txt" LEGACY_ECSTORE_CONFIG_MODEL_HITS_FILE="${TMP_DIR}/legacy_ecstore_config_model_hits.txt"
ECSTORE_ROOT_STORE_SET_DISK_MODULE_HITS_FILE="${TMP_DIR}/ecstore_root_store_set_disk_module_hits.txt" ECSTORE_ROOT_STORE_SET_DISK_MODULE_HITS_FILE="${TMP_DIR}/ecstore_root_store_set_disk_module_hits.txt"
ECSTORE_ROOT_STORE_SUPPORT_MODULE_HITS_FILE="${TMP_DIR}/ecstore_root_store_support_module_hits.txt" ECSTORE_ROOT_STORE_SUPPORT_MODULE_HITS_FILE="${TMP_DIR}/ecstore_root_store_support_module_hits.txt"
@@ -2277,6 +2278,18 @@ if [[ -s "$EXTERNAL_ECSTORE_API_BOUNDARY_HITS_FILE" ]]; then
report_failure "external ECStore API facade imports must stay in local storage_api boundary files: $(paste -sd '; ' "$EXTERNAL_ECSTORE_API_BOUNDARY_HITS_FILE")" report_failure "external ECStore API facade imports must stay in local storage_api boundary files: $(paste -sd '; ' "$EXTERNAL_ECSTORE_API_BOUNDARY_HITS_FILE")"
fi fi
(
cd "$ROOT_DIR"
rg -n --with-filename 'rustfs_ecstore::api::bucket::replication' \
rustfs/src crates/*/src crates/*/tests crates/ecstore/tests fuzz/fuzz_targets \
--glob '*.rs' |
rg -v '^(rustfs/src/(admin/storage_api|app/storage_api|storage/storage_api)\.rs|crates/ecstore/tests/storage_api\.rs|crates/obs/src/metrics/storage_api\.rs|crates/scanner/src/storage_api\.rs|crates/scanner/tests/storage_api/mod\.rs|fuzz/fuzz_targets/(bucket_validation_storage_api|path_containment_storage_api)\.rs):' || true
) >"$REPLICATION_FACADE_BYPASS_HITS_FILE"
if [[ -s "$REPLICATION_FACADE_BYPASS_HITS_FILE" ]]; then
report_failure "replication facade imports must stay in local storage_api boundaries: $(paste -sd '; ' "$REPLICATION_FACADE_BYPASS_HITS_FILE")"
fi
( (
cd "$ROOT_DIR" cd "$ROOT_DIR"
{ {