mod common;
use test_bd::{Bucket, DeviceManager, IndexPos, TestBlockDeviceConfig};
#[test]
fn test_device_manager_create_and_delete() {
let mut manager = DeviceManager::new();
let config = TestBlockDeviceConfig {
dev_id: 0, size: 10 * 1024 * 1024, seed: 12345,
fill_percent: 25,
duplicate_percent: 50,
random_percent: 25,
segments: 50,
unprivileged: true,
};
let device = manager.create(config).expect("Failed to create device");
assert_eq!(device.dev_id, 0, "Device ID should be 0 as requested");
assert_eq!(device.segments.len(), 50, "Should have 50 segments");
assert_eq!(device.config.size, 10 * 1024 * 1024, "Size should match");
let device_path = format!("/dev/ublkb{}", device.dev_id);
assert!(
std::path::Path::new(&device_path).exists(),
"Device file should exist"
);
manager
.delete(device.dev_id)
.expect("Failed to delete device");
std::thread::sleep(std::time::Duration::from_millis(100));
assert!(
!std::path::Path::new(&device_path).exists(),
"Device file should be removed"
);
}
#[test]
fn test_device_manager_multiple_devices() {
let mut manager = DeviceManager::new();
let config1 = TestBlockDeviceConfig {
dev_id: 0, size: 10 * 1024 * 1024,
seed: 11111,
fill_percent: 25,
duplicate_percent: 50,
random_percent: 25,
segments: 50,
unprivileged: true,
};
let config2 = TestBlockDeviceConfig {
dev_id: 1, size: 20 * 1024 * 1024,
seed: 22222,
fill_percent: 30,
duplicate_percent: 40,
random_percent: 30,
segments: 100,
unprivileged: true,
};
let device1 = manager.create(config1).expect("Failed to create device 1");
let device2 = manager.create(config2).expect("Failed to create device 2");
assert_eq!(device1.dev_id, 0, "Device 1 should have ID 0");
assert_eq!(device2.dev_id, 1, "Device 2 should have ID 1");
let devices = manager.list();
assert_eq!(devices.len(), 2, "Should have 2 managed devices");
assert!(std::path::Path::new(&format!("/dev/ublkb{}", device1.dev_id)).exists());
assert!(std::path::Path::new(&format!("/dev/ublkb{}", device2.dev_id)).exists());
manager.delete_all().expect("Failed to delete all devices");
assert_eq!(
manager.list().len(),
0,
"All devices should be removed from manager"
);
}
#[test]
fn test_device_manager_auto_cleanup_on_drop() {
let config = TestBlockDeviceConfig {
dev_id: 0, size: 10 * 1024 * 1024,
seed: 99999,
fill_percent: 25,
duplicate_percent: 50,
random_percent: 25,
segments: 50,
unprivileged: true,
};
let dev_id = {
let mut manager = DeviceManager::new();
let device = manager.create(config).expect("Failed to create device");
let device_path = format!("/dev/ublkb{}", device.dev_id);
assert!(
std::path::Path::new(&device_path).exists(),
"Device should exist"
);
device.dev_id
};
std::thread::sleep(std::time::Duration::from_millis(200));
let device_path = format!("/dev/ublkb{}", dev_id);
assert!(
!std::path::Path::new(&device_path).exists(),
"Device should be cleaned up when manager is dropped"
);
}
#[test]
fn test_segment_info_verification() {
let mut manager = DeviceManager::new();
let config = TestBlockDeviceConfig {
dev_id: 0, size: 10 * 1024 * 1024,
seed: 42,
fill_percent: 25,
duplicate_percent: 50,
random_percent: 25,
segments: 100,
unprivileged: true,
};
let device = manager
.create(config.clone())
.expect("Failed to create device");
let mut total_size = 0u64;
let mut last_end = IndexPos::new(0);
for segment in &device.segments {
assert_eq!(segment.start, last_end, "Segments should be contiguous");
assert!(segment.end > segment.start, "Segment end should be > start");
assert_eq!(segment.count(), segment.end - segment.start);
total_size += segment.size_bytes();
last_end = segment.end;
}
assert_eq!(
total_size, config.size,
"Segments should cover entire device"
);
assert_eq!(
last_end,
IndexPos::new(config.size / 8),
"Last segment should end at device size"
);
let fill_count = device
.segments
.iter()
.filter(|s| s.pattern == Bucket::Fill)
.count();
let dup_count = device
.segments
.iter()
.filter(|s| s.pattern == Bucket::Duplicate)
.count();
let rand_count = device
.segments
.iter()
.filter(|s| s.pattern == Bucket::Random)
.count();
assert_eq!(
fill_count + dup_count + rand_count,
100,
"Should have 100 total segments"
);
let expected_fill = 25;
let expected_dup = 50;
let expected_rand = 25;
assert!(
(fill_count as i32 - expected_fill).abs() <= 1,
"Fill segments should be close to 25%, got {}",
fill_count
);
assert!(
(dup_count as i32 - expected_dup).abs() <= 1,
"Duplicate segments should be close to 50%, got {}",
dup_count
);
assert!(
(rand_count as i32 - expected_rand).abs() <= 1,
"Random segments should be close to 25%, got {}",
rand_count
);
manager
.delete(device.dev_id)
.expect("Failed to delete device");
}
#[test]
fn test_generate_segments_without_creating_device() {
let config = TestBlockDeviceConfig {
dev_id: -1,
size: 10 * 1024 * 1024,
seed: 12345,
fill_percent: 25,
duplicate_percent: 50,
random_percent: 25,
segments: 100,
unprivileged: true,
};
let segments = config.generate_segments();
assert_eq!(segments.len(), 100, "Should generate 100 segments");
let mut total_size = 0u64;
for (i, segment) in segments.iter().enumerate() {
if i > 0 {
assert_eq!(
segment.start,
segments[i - 1].end,
"Segments should be contiguous"
);
}
total_size += segment.size_bytes();
}
assert_eq!(
total_size, config.size,
"Segments should cover entire device"
);
}
#[test]
fn test_config_validation() {
let valid_config = TestBlockDeviceConfig {
dev_id: -1,
size: 10 * 1024 * 1024,
seed: 12345,
fill_percent: 25,
duplicate_percent: 50,
random_percent: 25,
segments: 100,
unprivileged: true,
};
assert!(valid_config.validate().is_ok());
let invalid_percent_config = TestBlockDeviceConfig {
dev_id: -1,
size: 10 * 1024 * 1024,
seed: 12345,
fill_percent: 25,
duplicate_percent: 50,
random_percent: 30, segments: 100,
unprivileged: true,
};
assert!(invalid_percent_config.validate().is_err());
let invalid_segments_config = TestBlockDeviceConfig {
dev_id: -1,
size: 1024, seed: 12345,
fill_percent: 25,
duplicate_percent: 50,
random_percent: 25,
segments: 10000, unprivileged: true,
};
assert!(invalid_segments_config.validate().is_err());
}