use std::fs::read_dir;
use aok::{OK, Void};
use compio::runtime::Runtime;
use log::info;
use tempfile::tempdir;
use wbase::{align::DEFAULT_SECTOR_SIZE, pool::AlignedBuf};
use wdev::{
Device, DeviceParams, Error, MAX_SEGMENT_SIZE, SegmentedDevice, detect_cpu_cores,
detect_system_memory,
};
#[test]
fn construction_rejects_non_multiple_of_segment_size() -> Void {
let dir = tempdir()?;
let seg_size: u64 = 64 * 1024;
for bad in [0u64, seg_size * 2 + 123] {
let err = SegmentedDevice::with_params(
dir.path().join(format!("cap_invalid_{bad}.log")),
Some(seg_size),
DEFAULT_SECTOR_SIZE,
DeviceParams {
capacity: Some(bad),
..DeviceParams::default()
},
)
.err()
.expect("非法容量必须构造失败");
assert!(
matches!(err, Error::InvalidCapacity { capacity } if capacity == bad),
"非法容量 {bad} 实际报 {err:?}"
);
}
assert_eq!(read_dir(dir.path())?.count(), 0, "非法容量构造必须零产物");
let device = SegmentedDevice::with_params(
dir.path().join("cap_valid.log"),
Some(seg_size),
DEFAULT_SECTOR_SIZE,
DeviceParams {
capacity: Some(seg_size * 2),
..DeviceParams::default()
},
)?;
assert_eq!(device.capacity(), Some(seg_size * 2));
assert_eq!(Device::capacity(&device), Some(seg_size * 2));
info!("容量上限整数倍校验通过 (构造期 capacity 校验)");
OK
}
#[test]
fn handle_capacity_evicts_oldest_segments_when_bounded() -> Void {
let rt = Runtime::new()?;
rt.block_on(async {
let dir = tempdir()?;
let seg_size: u64 = 64 * 1024;
let device = SegmentedDevice::with_params(
dir.path().join("cap_evict.log"),
Some(seg_size),
DEFAULT_SECTOR_SIZE,
DeviceParams {
capacity: Some(seg_size * 2),
..DeviceParams::default()
},
)?;
assert_eq!(
device.end_segment(),
None,
"初始 end_segment 应为 None (C# -1)"
);
for seg_id in 0..4u32 {
let buf = AlignedBuf::from_slice(&[(seg_id * 17 + 1) as u8; 4096], 4096)?;
let (res, _) = device.write_aligned((seg_id as u64) * seg_size, buf).await;
assert_eq!(res?, 4096);
}
assert_eq!(
device.start_segment(),
1,
"段 0 被逐出后 start_segment 应为 1"
);
assert_eq!(device.end_segment(), Some(3));
assert!(
!device.segment_path(0).exists(),
"超容量的最老段必须被 HandleCapacity 自动物理删除"
);
assert_eq!(device.get_file_size(0)?, 0);
for seg_id in 1..4u32 {
assert!(device.segment_path(seg_id).exists(), "段 {seg_id} 应保留");
let expected = (seg_id * 17 + 1) as u8;
let check = AlignedBuf::new(4096, 4096)?;
let (res, check) = device.read_aligned((seg_id as u64) * seg_size, check).await;
assert_eq!(res?, 4096);
assert!(check.as_slice().iter().all(|&b| b == expected));
}
info!("有界容量自动逐出最老段校验通过 (HandleCapacity)");
aok::Result::<()>::Ok(())
})?;
OK
}
#[test]
fn segment_size_above_max_is_rejected() -> Void {
let rt = Runtime::new()?;
rt.block_on(async {
let dir = tempdir()?;
assert!(matches!(
SegmentedDevice::new(dir.path().join("seg_max1.log"), Some(1u64 << 63), 4096),
Err(Error::InvalidSegmentSize(_))
));
assert!(matches!(
SegmentedDevice::new(
dir.path().join("seg_max2.log"),
Some(MAX_SEGMENT_SIZE + 1),
4096
),
Err(Error::InvalidSegmentSize(_))
));
let device = SegmentedDevice::new(
dir.path().join("seg_max_ok.log"),
Some(MAX_SEGMENT_SIZE),
4096,
)?;
assert_eq!(device.segment_size(), Some(MAX_SEGMENT_SIZE));
info!("段尺寸上界防御校验通过 (MAX_SEGMENT_SIZE)");
aok::Result::<()>::Ok(())
})?;
OK
}
#[test]
fn single_file_bounded_capacity_rejects_out_of_bounds_writes() -> Void {
let rt = Runtime::new()?;
rt.block_on(async {
let dir = tempdir()?;
let cap = 4096u64 * 2;
let device = SegmentedDevice::with_params(
dir.path().join("cap_single.log"),
None,
DEFAULT_SECTOR_SIZE,
DeviceParams {
capacity: Some(cap),
..DeviceParams::default()
},
)?;
assert_eq!(device.capacity(), Some(cap));
let buf = AlignedBuf::from_slice(&[0x21u8; 4096], 4096)?;
let (res, _) = device.write_aligned(0, buf).await;
assert_eq!(res?, 4096);
let buf = AlignedBuf::from_slice(&[0x22u8; 4096], 4096)?;
let (res, _) = device.write_aligned(4096, buf).await;
assert_eq!(res?, 4096);
let buf = AlignedBuf::from_slice(&[0x23u8; 4096], 4096)?;
let (res, _) = device.write_aligned(8192, buf).await;
assert!(
matches!(
res,
Err(Error::OutOfBounds {
offset: 8192,
len: 4096
})
),
"单文件模式容量越界写入必须返回 OutOfBounds,实际为 {res:?}"
);
let buf = AlignedBuf::from_slice(&[0x24u8; 4096], 4096)?;
let (res, _) = device.write_aligned(u64::MAX - 4095, buf).await;
assert!(matches!(res, Err(Error::OutOfBounds { .. })));
info!("单文件有界容量硬上界防御校验通过");
aok::Result::<()>::Ok(())
})?;
OK
}
#[test]
fn system_probes_return_usable_values() -> Void {
let sys_mem = detect_system_memory();
assert!(sys_mem > 0, "系统内存探测值必须大于 0");
let cores = detect_cpu_cores();
assert!(cores >= 1, "可用 CPU 核心数必须至少为 1");
info!("系统内存/核心数探测校验通过");
OK
}