mirror of
https://github.com/rustfs/rustfs.git
synced 2026-08-17 10:17:55 +00:00
1eef0de003
* chore(ecstore): drop the disk dead_code blanket Removing the blanket exposes 36 items in the lowest storage layer: 7 deleted, 29 kept with reasoned item-level allows. That is the smallest deletion share of this burn-down, and the reason is a verification limit rather than a judgement call. disk/local.rs carries 141 `#[cfg(target_os = "linux")]` sites — the densest platform gating in the tree, because O_DIRECT and io_uring only exist there. The direct-I/O cluster (six ENV_RUSTFS_OBJECT_DIRECT_IO_* constants plus is_direct_io_read_enabled, is_direct_io_write_enabled, get_direct_io_read_threshold, direct_write_staging_capacity, direct_write_tail_split and DIRECT_WRITE_STAGING_BYTES) reads as dead on macOS purely because its production callers at local.rs:1766, 3114 and 4605 sit inside Linux-gated blocks. direct_write_staging_capacity even documents itself as "Platform-independent (no O_DIRECT), so it is unit-tested on any host". Deleting those would leave every local check green — 4096 tests pass, clippy is clean, make pre-commit exits 0 — and break the Linux build in CI, because all four local lanes compile for aarch64-apple-darwin. Cross-checking locally is not available either: cargo check --target x86_64-unknown-linux-gnu fails in the aws-lc-sys build script for want of a Linux C cross-compiler. Their allows name the platform reason so the next reader on a non-Linux host does not repeat the investigation. Deleted, all in files with no target_os gating at all (os.rs, disk_store.rs): - HealthDiskCtxKey and HealthDiskCtxValue with its private log_success. Note that DiskHealthTracker::log_success is a different method of the same name and is live from cluster/rpc/peer_s3_client.rs and remote_disk.rs — the two have to be told apart by type, not by name. - LocalDiskWrapper::new_with_health and check_id. - os.rs file_exists and lock_destination_directory_for_path_access. Kept with allows: DiskHealthTracker's set_faulty, mark_offline, waiting_count and last_success have test callers in remote_disk.rs, so they only look dead in the lib target. to_disk_error, remove_all and sync_dir_files are asserted by their own files' tests. The reclaim, mmap and path-cache field groups are written but never read back. Placement follows the same rule as the earlier roots: per-method allows inside impl DiskHealthTracker and impl LocalDisk, since both are mostly live and a block-level allow would be a smaller version of the blanket this issue removes. Struct-level allows are used only where the warning covers that struct's own fields. The three cached_read_env! functions take their allow inside the macro invocation, before the fn line, because the macro forwards $(#[$meta:meta])* onto the generated item. Verification, four lanes warning-free: default, --tests, --features rio-v2 --tests, --features test-util --tests. cargo nextest run -p rustfs-ecstore 4096 passed; clippy --lib --tests -D warnings clean; make pre-commit exit 0. The Linux lane is not covered locally and is left to CI. Ref rustfs/backlog#1823 (step 2). * chore(ecstore): correct two dead_code reasons in the disk root check_valid_path and reject_symlink_components have no caller at all - not even a test - so 'asserted by this file's tests' misreads them as covered. Both are method wrappers over live free functions; say that instead. Ref rustfs/backlog#1823.
453 lines
20 KiB
Rust
453 lines
20 KiB
Rust
// 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.
|
|
|
|
use crate::disk::error::DiskError;
|
|
|
|
pub fn to_file_error(io_err: std::io::Error) -> std::io::Error {
|
|
match io_err.kind() {
|
|
std::io::ErrorKind::NotFound => DiskError::FileNotFound.into(),
|
|
std::io::ErrorKind::PermissionDenied => DiskError::FileAccessDenied.into(),
|
|
std::io::ErrorKind::IsADirectory => DiskError::IsNotRegular.into(),
|
|
std::io::ErrorKind::NotADirectory => DiskError::FileAccessDenied.into(),
|
|
std::io::ErrorKind::DirectoryNotEmpty => DiskError::FileAccessDenied.into(),
|
|
std::io::ErrorKind::UnexpectedEof => DiskError::FaultyDisk.into(),
|
|
std::io::ErrorKind::TooManyLinks => DiskError::TooManyOpenFiles.into(),
|
|
std::io::ErrorKind::InvalidInput => DiskError::FileNotFound.into(),
|
|
std::io::ErrorKind::InvalidData => DiskError::FileCorrupt.into(),
|
|
std::io::ErrorKind::StorageFull => DiskError::DiskFull.into(),
|
|
_ => io_err,
|
|
}
|
|
}
|
|
|
|
pub fn to_volume_error(io_err: std::io::Error) -> std::io::Error {
|
|
match io_err.kind() {
|
|
std::io::ErrorKind::NotFound => DiskError::VolumeNotFound.into(),
|
|
std::io::ErrorKind::PermissionDenied => DiskError::DiskAccessDenied.into(),
|
|
std::io::ErrorKind::DirectoryNotEmpty => DiskError::VolumeNotEmpty.into(),
|
|
std::io::ErrorKind::NotADirectory => DiskError::IsNotRegular.into(),
|
|
std::io::ErrorKind::Other => match io_err.downcast::<DiskError>() {
|
|
Ok(err) => match err {
|
|
DiskError::FileNotFound => DiskError::VolumeNotFound.into(),
|
|
DiskError::FileAccessDenied => DiskError::DiskAccessDenied.into(),
|
|
err => err.into(),
|
|
},
|
|
Err(err) => to_file_error(err),
|
|
},
|
|
_ => to_file_error(io_err),
|
|
}
|
|
}
|
|
|
|
#[allow(dead_code, reason = "asserted by this file's tests (backlog#1823)")]
|
|
pub fn to_disk_error(io_err: std::io::Error) -> std::io::Error {
|
|
match io_err.kind() {
|
|
std::io::ErrorKind::NotFound => DiskError::DiskNotFound.into(),
|
|
std::io::ErrorKind::PermissionDenied => DiskError::DiskAccessDenied.into(),
|
|
std::io::ErrorKind::Other => match io_err.downcast::<DiskError>() {
|
|
Ok(err) => match err {
|
|
DiskError::FileNotFound => DiskError::DiskNotFound.into(),
|
|
DiskError::VolumeNotFound => DiskError::DiskNotFound.into(),
|
|
DiskError::FileAccessDenied => DiskError::DiskAccessDenied.into(),
|
|
DiskError::VolumeAccessDenied => DiskError::DiskAccessDenied.into(),
|
|
err => err.into(),
|
|
},
|
|
Err(err) => to_volume_error(err),
|
|
},
|
|
_ => to_volume_error(io_err),
|
|
}
|
|
}
|
|
|
|
// only errors from FileSystem operations
|
|
pub fn to_access_error(io_err: std::io::Error, per_err: DiskError) -> std::io::Error {
|
|
match io_err.kind() {
|
|
std::io::ErrorKind::PermissionDenied => per_err.into(),
|
|
std::io::ErrorKind::NotADirectory => per_err.into(),
|
|
std::io::ErrorKind::NotFound => DiskError::VolumeNotFound.into(),
|
|
std::io::ErrorKind::UnexpectedEof => DiskError::FaultyDisk.into(),
|
|
std::io::ErrorKind::Other => match io_err.downcast::<DiskError>() {
|
|
Ok(err) => match err {
|
|
DiskError::DiskAccessDenied => per_err.into(),
|
|
DiskError::FileAccessDenied => per_err.into(),
|
|
DiskError::FileNotFound => DiskError::VolumeNotFound.into(),
|
|
err => err.into(),
|
|
},
|
|
Err(err) => to_volume_error(err),
|
|
},
|
|
_ => to_volume_error(io_err),
|
|
}
|
|
}
|
|
|
|
pub fn to_unformatted_disk_error(io_err: std::io::Error) -> std::io::Error {
|
|
match io_err.kind() {
|
|
std::io::ErrorKind::NotFound => DiskError::UnformattedDisk.into(),
|
|
std::io::ErrorKind::PermissionDenied => DiskError::DiskAccessDenied.into(),
|
|
std::io::ErrorKind::UnexpectedEof => DiskError::UnformattedDisk.into(),
|
|
std::io::ErrorKind::InvalidData => DiskError::UnformattedDisk.into(),
|
|
std::io::ErrorKind::Other => match io_err.downcast::<DiskError>() {
|
|
Ok(err) => match err {
|
|
DiskError::FileNotFound => DiskError::UnformattedDisk.into(),
|
|
DiskError::DiskNotFound => DiskError::UnformattedDisk.into(),
|
|
DiskError::VolumeNotFound => DiskError::UnformattedDisk.into(),
|
|
DiskError::FileAccessDenied => DiskError::DiskAccessDenied.into(),
|
|
DiskError::DiskAccessDenied => DiskError::DiskAccessDenied.into(),
|
|
_ => DiskError::UnformattedDisk.into(),
|
|
},
|
|
Err(_err) => DiskError::UnformattedDisk.into(),
|
|
},
|
|
_ => DiskError::UnformattedDisk.into(),
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
use std::io::{Error as IoError, ErrorKind};
|
|
|
|
// Helper function to create IO errors with specific kinds
|
|
fn create_io_error(kind: ErrorKind) -> IoError {
|
|
IoError::new(kind, "test error")
|
|
}
|
|
|
|
// Helper function to create IO errors with DiskError as the source
|
|
fn create_io_error_with_disk_error(disk_error: DiskError) -> IoError {
|
|
IoError::other(disk_error)
|
|
}
|
|
|
|
// Helper function to check if an IoError contains a specific DiskError
|
|
fn contains_disk_error(io_error: IoError, expected: DiskError) -> bool {
|
|
if let Ok(disk_error) = io_error.downcast::<DiskError>() {
|
|
std::mem::discriminant(&disk_error) == std::mem::discriminant(&expected)
|
|
} else {
|
|
false
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn test_to_file_error_basic_conversions() {
|
|
// Test NotFound -> FileNotFound
|
|
let result = to_file_error(create_io_error(ErrorKind::NotFound));
|
|
assert!(contains_disk_error(result, DiskError::FileNotFound));
|
|
|
|
// Test PermissionDenied -> FileAccessDenied
|
|
let result = to_file_error(create_io_error(ErrorKind::PermissionDenied));
|
|
assert!(contains_disk_error(result, DiskError::FileAccessDenied));
|
|
|
|
// Test IsADirectory -> IsNotRegular
|
|
let result = to_file_error(create_io_error(ErrorKind::IsADirectory));
|
|
assert!(contains_disk_error(result, DiskError::IsNotRegular));
|
|
|
|
// Test NotADirectory -> FileAccessDenied
|
|
let result = to_file_error(create_io_error(ErrorKind::NotADirectory));
|
|
assert!(contains_disk_error(result, DiskError::FileAccessDenied));
|
|
|
|
// Test DirectoryNotEmpty -> FileAccessDenied
|
|
let result = to_file_error(create_io_error(ErrorKind::DirectoryNotEmpty));
|
|
assert!(contains_disk_error(result, DiskError::FileAccessDenied));
|
|
|
|
// Test UnexpectedEof -> FaultyDisk
|
|
let result = to_file_error(create_io_error(ErrorKind::UnexpectedEof));
|
|
assert!(contains_disk_error(result, DiskError::FaultyDisk));
|
|
|
|
// Test TooManyLinks -> TooManyOpenFiles
|
|
#[cfg(unix)]
|
|
{
|
|
let result = to_file_error(create_io_error(ErrorKind::TooManyLinks));
|
|
assert!(contains_disk_error(result, DiskError::TooManyOpenFiles));
|
|
}
|
|
|
|
// Test InvalidInput -> FileNotFound
|
|
let result = to_file_error(create_io_error(ErrorKind::InvalidInput));
|
|
assert!(contains_disk_error(result, DiskError::FileNotFound));
|
|
|
|
// Test InvalidData -> FileCorrupt
|
|
let result = to_file_error(create_io_error(ErrorKind::InvalidData));
|
|
assert!(contains_disk_error(result, DiskError::FileCorrupt));
|
|
|
|
// Test StorageFull -> DiskFull
|
|
#[cfg(unix)]
|
|
{
|
|
let result = to_file_error(create_io_error(ErrorKind::StorageFull));
|
|
assert!(contains_disk_error(result, DiskError::DiskFull));
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn test_to_file_error_passthrough_unknown() {
|
|
// Test that unknown error kinds are passed through unchanged
|
|
let original = create_io_error(ErrorKind::Interrupted);
|
|
let result = to_file_error(original);
|
|
assert_eq!(result.kind(), ErrorKind::Interrupted);
|
|
}
|
|
|
|
#[test]
|
|
fn test_to_volume_error_basic_conversions() {
|
|
// Test NotFound -> VolumeNotFound
|
|
let result = to_volume_error(create_io_error(ErrorKind::NotFound));
|
|
assert!(contains_disk_error(result, DiskError::VolumeNotFound));
|
|
|
|
// Test PermissionDenied -> DiskAccessDenied
|
|
let result = to_volume_error(create_io_error(ErrorKind::PermissionDenied));
|
|
assert!(contains_disk_error(result, DiskError::DiskAccessDenied));
|
|
|
|
// Test DirectoryNotEmpty -> VolumeNotEmpty
|
|
let result = to_volume_error(create_io_error(ErrorKind::DirectoryNotEmpty));
|
|
assert!(contains_disk_error(result, DiskError::VolumeNotEmpty));
|
|
|
|
// Test NotADirectory -> IsNotRegular
|
|
let result = to_volume_error(create_io_error(ErrorKind::NotADirectory));
|
|
assert!(contains_disk_error(result, DiskError::IsNotRegular));
|
|
}
|
|
|
|
#[test]
|
|
fn test_to_volume_error_other_with_disk_error() {
|
|
// Test Other error kind with FileNotFound DiskError -> VolumeNotFound
|
|
let io_error = create_io_error_with_disk_error(DiskError::FileNotFound);
|
|
let result = to_volume_error(io_error);
|
|
assert!(contains_disk_error(result, DiskError::VolumeNotFound));
|
|
|
|
// Test Other error kind with FileAccessDenied DiskError -> DiskAccessDenied
|
|
let io_error = create_io_error_with_disk_error(DiskError::FileAccessDenied);
|
|
let result = to_volume_error(io_error);
|
|
assert!(contains_disk_error(result, DiskError::DiskAccessDenied));
|
|
|
|
// Test Other error kind with other DiskError -> passthrough
|
|
let io_error = create_io_error_with_disk_error(DiskError::DiskFull);
|
|
let result = to_volume_error(io_error);
|
|
assert!(contains_disk_error(result, DiskError::DiskFull));
|
|
}
|
|
|
|
#[test]
|
|
fn test_to_volume_error_fallback_to_file_error() {
|
|
// Test fallback to to_file_error for unknown error kinds
|
|
let result = to_volume_error(create_io_error(ErrorKind::Interrupted));
|
|
assert_eq!(result.kind(), ErrorKind::Interrupted);
|
|
}
|
|
|
|
#[test]
|
|
fn test_to_disk_error_basic_conversions() {
|
|
// Test NotFound -> DiskNotFound
|
|
let result = to_disk_error(create_io_error(ErrorKind::NotFound));
|
|
assert!(contains_disk_error(result, DiskError::DiskNotFound));
|
|
|
|
// Test PermissionDenied -> DiskAccessDenied
|
|
let result = to_disk_error(create_io_error(ErrorKind::PermissionDenied));
|
|
assert!(contains_disk_error(result, DiskError::DiskAccessDenied));
|
|
}
|
|
|
|
#[test]
|
|
fn test_to_disk_error_other_with_disk_error() {
|
|
// Test Other error kind with FileNotFound DiskError -> DiskNotFound
|
|
let io_error = create_io_error_with_disk_error(DiskError::FileNotFound);
|
|
let result = to_disk_error(io_error);
|
|
assert!(contains_disk_error(result, DiskError::DiskNotFound));
|
|
|
|
// Test Other error kind with VolumeNotFound DiskError -> DiskNotFound
|
|
let io_error = create_io_error_with_disk_error(DiskError::VolumeNotFound);
|
|
let result = to_disk_error(io_error);
|
|
assert!(contains_disk_error(result, DiskError::DiskNotFound));
|
|
|
|
// Test Other error kind with FileAccessDenied DiskError -> DiskAccessDenied
|
|
let io_error = create_io_error_with_disk_error(DiskError::FileAccessDenied);
|
|
let result = to_disk_error(io_error);
|
|
assert!(contains_disk_error(result, DiskError::DiskAccessDenied));
|
|
|
|
// Test Other error kind with VolumeAccessDenied DiskError -> DiskAccessDenied
|
|
let io_error = create_io_error_with_disk_error(DiskError::VolumeAccessDenied);
|
|
let result = to_disk_error(io_error);
|
|
assert!(contains_disk_error(result, DiskError::DiskAccessDenied));
|
|
|
|
// Test Other error kind with other DiskError -> passthrough
|
|
let io_error = create_io_error_with_disk_error(DiskError::DiskFull);
|
|
let result = to_disk_error(io_error);
|
|
assert!(contains_disk_error(result, DiskError::DiskFull));
|
|
}
|
|
|
|
#[test]
|
|
fn test_to_disk_error_fallback_to_volume_error() {
|
|
// Test fallback to to_volume_error for unknown error kinds
|
|
let result = to_disk_error(create_io_error(ErrorKind::Interrupted));
|
|
assert_eq!(result.kind(), ErrorKind::Interrupted);
|
|
}
|
|
|
|
#[test]
|
|
fn test_to_access_error_basic_conversions() {
|
|
let permission_error = DiskError::FileAccessDenied;
|
|
|
|
// Test PermissionDenied -> specified permission error
|
|
let result = to_access_error(create_io_error(ErrorKind::PermissionDenied), permission_error);
|
|
assert!(contains_disk_error(result, DiskError::FileAccessDenied));
|
|
|
|
// Test NotADirectory -> specified permission error
|
|
let result = to_access_error(create_io_error(ErrorKind::NotADirectory), DiskError::FileAccessDenied);
|
|
assert!(contains_disk_error(result, DiskError::FileAccessDenied));
|
|
|
|
// Test NotFound -> VolumeNotFound
|
|
let result = to_access_error(create_io_error(ErrorKind::NotFound), DiskError::FileAccessDenied);
|
|
assert!(contains_disk_error(result, DiskError::VolumeNotFound));
|
|
|
|
// Test UnexpectedEof -> FaultyDisk
|
|
let result = to_access_error(create_io_error(ErrorKind::UnexpectedEof), DiskError::FileAccessDenied);
|
|
assert!(contains_disk_error(result, DiskError::FaultyDisk));
|
|
}
|
|
|
|
#[test]
|
|
fn test_to_access_error_other_with_disk_error() {
|
|
let permission_error = DiskError::VolumeAccessDenied;
|
|
|
|
// Test Other error kind with DiskAccessDenied -> specified permission error
|
|
let io_error = create_io_error_with_disk_error(DiskError::DiskAccessDenied);
|
|
let result = to_access_error(io_error, permission_error);
|
|
assert!(contains_disk_error(result, DiskError::VolumeAccessDenied));
|
|
|
|
// Test Other error kind with FileAccessDenied -> specified permission error
|
|
let io_error = create_io_error_with_disk_error(DiskError::FileAccessDenied);
|
|
let result = to_access_error(io_error, DiskError::VolumeAccessDenied);
|
|
assert!(contains_disk_error(result, DiskError::VolumeAccessDenied));
|
|
|
|
// Test Other error kind with FileNotFound -> VolumeNotFound
|
|
let io_error = create_io_error_with_disk_error(DiskError::FileNotFound);
|
|
let result = to_access_error(io_error, DiskError::VolumeAccessDenied);
|
|
assert!(contains_disk_error(result, DiskError::VolumeNotFound));
|
|
|
|
// Test Other error kind with other DiskError -> passthrough
|
|
let io_error = create_io_error_with_disk_error(DiskError::DiskFull);
|
|
let result = to_access_error(io_error, DiskError::VolumeAccessDenied);
|
|
assert!(contains_disk_error(result, DiskError::DiskFull));
|
|
}
|
|
|
|
#[test]
|
|
fn test_to_access_error_fallback_to_volume_error() {
|
|
let permission_error = DiskError::FileAccessDenied;
|
|
|
|
// Test fallback to to_volume_error for unknown error kinds
|
|
let result = to_access_error(create_io_error(ErrorKind::Interrupted), permission_error);
|
|
assert_eq!(result.kind(), ErrorKind::Interrupted);
|
|
}
|
|
|
|
#[test]
|
|
fn test_to_unformatted_disk_error_basic_conversions() {
|
|
// Test NotFound -> UnformattedDisk
|
|
let result = to_unformatted_disk_error(create_io_error(ErrorKind::NotFound));
|
|
assert!(contains_disk_error(result, DiskError::UnformattedDisk));
|
|
|
|
// Test PermissionDenied -> DiskAccessDenied
|
|
let result = to_unformatted_disk_error(create_io_error(ErrorKind::PermissionDenied));
|
|
assert!(contains_disk_error(result, DiskError::DiskAccessDenied));
|
|
}
|
|
|
|
#[test]
|
|
fn test_to_unformatted_disk_error_other_with_disk_error() {
|
|
// Test Other error kind with FileNotFound -> UnformattedDisk
|
|
let io_error = create_io_error_with_disk_error(DiskError::FileNotFound);
|
|
let result = to_unformatted_disk_error(io_error);
|
|
assert!(contains_disk_error(result, DiskError::UnformattedDisk));
|
|
|
|
// Test Other error kind with DiskNotFound -> UnformattedDisk
|
|
let io_error = create_io_error_with_disk_error(DiskError::DiskNotFound);
|
|
let result = to_unformatted_disk_error(io_error);
|
|
assert!(contains_disk_error(result, DiskError::UnformattedDisk));
|
|
|
|
// Test Other error kind with VolumeNotFound -> UnformattedDisk
|
|
let io_error = create_io_error_with_disk_error(DiskError::VolumeNotFound);
|
|
let result = to_unformatted_disk_error(io_error);
|
|
assert!(contains_disk_error(result, DiskError::UnformattedDisk));
|
|
|
|
// Test Other error kind with FileAccessDenied -> DiskAccessDenied
|
|
let io_error = create_io_error_with_disk_error(DiskError::FileAccessDenied);
|
|
let result = to_unformatted_disk_error(io_error);
|
|
assert!(contains_disk_error(result, DiskError::DiskAccessDenied));
|
|
|
|
// Test Other error kind with DiskAccessDenied -> DiskAccessDenied
|
|
let io_error = create_io_error_with_disk_error(DiskError::DiskAccessDenied);
|
|
let result = to_unformatted_disk_error(io_error);
|
|
assert!(contains_disk_error(result, DiskError::DiskAccessDenied));
|
|
|
|
// Test Other error kind with other DiskError -> UnformattedDisk
|
|
let io_error = create_io_error_with_disk_error(DiskError::DiskFull);
|
|
let result = to_unformatted_disk_error(io_error);
|
|
assert!(contains_disk_error(result, DiskError::UnformattedDisk));
|
|
}
|
|
|
|
#[test]
|
|
fn test_to_unformatted_disk_error_recursive_behavior() {
|
|
// Test with non-Other error kind that should be handled without infinite recursion
|
|
let result = to_unformatted_disk_error(create_io_error(ErrorKind::Interrupted));
|
|
// This should not cause infinite recursion and should produce UnformattedDisk
|
|
assert!(contains_disk_error(result, DiskError::UnformattedDisk));
|
|
}
|
|
|
|
#[test]
|
|
fn test_error_chain_conversions() {
|
|
// Test complex error conversion chains
|
|
let original_error = create_io_error(ErrorKind::NotFound);
|
|
|
|
// Chain: NotFound -> FileNotFound (via to_file_error) -> VolumeNotFound (via to_volume_error)
|
|
let file_error = to_file_error(original_error);
|
|
let volume_error = to_volume_error(file_error);
|
|
assert!(contains_disk_error(volume_error, DiskError::VolumeNotFound));
|
|
}
|
|
|
|
#[test]
|
|
fn test_cross_platform_error_kinds() {
|
|
// Test error kinds that may not be available on all platforms
|
|
#[cfg(unix)]
|
|
{
|
|
let result = to_file_error(create_io_error(ErrorKind::TooManyLinks));
|
|
assert!(contains_disk_error(result, DiskError::TooManyOpenFiles));
|
|
}
|
|
|
|
#[cfg(unix)]
|
|
{
|
|
let result = to_file_error(create_io_error(ErrorKind::StorageFull));
|
|
assert!(contains_disk_error(result, DiskError::DiskFull));
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn test_error_conversion_with_different_kinds() {
|
|
// Test multiple error kinds to ensure comprehensive coverage
|
|
let test_cases = vec![
|
|
(ErrorKind::NotFound, DiskError::FileNotFound),
|
|
(ErrorKind::PermissionDenied, DiskError::FileAccessDenied),
|
|
(ErrorKind::IsADirectory, DiskError::IsNotRegular),
|
|
(ErrorKind::InvalidData, DiskError::FileCorrupt),
|
|
];
|
|
|
|
for (kind, expected_disk_error) in test_cases {
|
|
let result = to_file_error(create_io_error(kind));
|
|
assert!(
|
|
contains_disk_error(result, expected_disk_error.clone()),
|
|
"Failed for ErrorKind::{kind:?} -> DiskError::{expected_disk_error:?}"
|
|
);
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn test_volume_error_conversion_chain() {
|
|
// Test volume error conversion with different input types
|
|
let test_cases = vec![
|
|
(ErrorKind::NotFound, DiskError::VolumeNotFound),
|
|
(ErrorKind::PermissionDenied, DiskError::DiskAccessDenied),
|
|
(ErrorKind::DirectoryNotEmpty, DiskError::VolumeNotEmpty),
|
|
];
|
|
|
|
for (kind, expected_disk_error) in test_cases {
|
|
let result = to_volume_error(create_io_error(kind));
|
|
assert!(
|
|
contains_disk_error(result, expected_disk_error.clone()),
|
|
"Failed for ErrorKind::{kind:?} -> DiskError::{expected_disk_error:?}"
|
|
);
|
|
}
|
|
}
|
|
}
|