| Crates.io | test-bd |
| lib.rs | test-bd |
| version | 0.2.0 |
| created_at | 2025-11-18 19:26:44.281215+00 |
| updated_at | 2025-11-18 19:26:44.281215+00 |
| description | A library and CLI tool for creating procedurally generated test block devices using ublk |
| homepage | https://github.com/tasleson/test-bd |
| repository | https://github.com/tasleson/test-bd |
| max_upload_size | |
| id | 1938890 |
| size | 221,977 |
A library and CLI tool for creating deterministic, procedurally generated test block devices using ublk (userspace block device). Perfect for testing storage management tools, backup utilities, compression algorithms, and deduplication systems.
Add to your Cargo.toml:
[dependencies]
test-bd = "0.1"
Create a test device:
use test_bd::{TestBlockDevice, TestBlockDeviceConfig};
fn main() {
let config = TestBlockDeviceConfig {
dev_id: -1, // Auto-allocate device ID
size: 1024 * 1024 * 1024, // 1 GiB
seed: 12345, // Deterministic seed
fill_percent: 25, // 25% fill (zeros)
duplicate_percent: 50, // 50% duplicate data
random_percent: 25, // 25% random data
segments: 100, // Split into 100 segments
unprivileged: true, // Run without root
};
// Validate configuration
config.validate().expect("Invalid configuration");
// Run the device (blocks until interrupted)
match TestBlockDevice::run(config) {
Ok(dev_id) => println!("Device /dev/ublkb{} created", dev_id),
Err(e) => eprintln!("Error: {}", e),
}
}
Create a test device:
# Create a 4 GiB device with default settings
test-bd add --size "4 GiB"
# Create with custom data distribution and JSON output
test-bd add --size "10 GiB" --fill 30 --duplicate 50 --random 20 --segments 1000 -J
# Delete a device
test-bd del --id 0
Create large test devices to verify backup tools correctly handle different data types:
use test_bd::{TestBlockDevice, TestBlockDeviceConfig};
// Create a 1 TiB device for backup testing
let config = TestBlockDeviceConfig {
dev_id: 0,
size: 1024u64 * 1024 * 1024 * 1024, // 1 TiB
seed: 42,
fill_percent: 30, // Empty space
duplicate_percent: 50, // Compressible data
random_percent: 20, // Incompressible data
segments: 1000,
unprivileged: true,
};
TestBlockDevice::run(config).unwrap();
// Device is now available at /dev/ublkb0
// Run: dd if=/dev/ublkb0 | your-backup-tool
Verify compression ratios with known data distributions:
# Create device with 80% duplicate data (should compress well)
test-bd add --size "10 GiB" --fill 10 --duplicate 80 --random 10 --seed 999
# Test compression
dd if=/dev/ublkb0 | gzip > compressed.gz
Same seed produces identical data every time:
# Device 1 with seed 12345
test-bd add --id 1 --size "1 GiB" --seed 12345
# Device 2 with same seed - identical data
test-bd add --id 2 --size "1 GiB" --seed 12345
# Verify they're identical
$ md5sum /dev/ublkb*
959b736ca6708c62797c0a2cb911e142 /dev/ublkb1
959b736ca6708c62797c0a2cb911e142 /dev/ublkb2
Get segment information when device is ready:
use test_bd::{TestBlockDevice, TestBlockDeviceConfig, Bucket};
let config = TestBlockDeviceConfig {
dev_id: 0,
size: 1024 * 1024 * 1024,
seed: 42,
fill_percent: 25,
duplicate_percent: 50,
random_percent: 25,
segments: 100,
unprivileged: true,
};
TestBlockDevice::run_with_callback(config, Some(|dev_id, segments| {
println!("Device {} ready with {} segments", dev_id, segments.len());
for seg in &segments {
match seg.pattern {
Bucket::Fill => println!("Fill: {}..{}", seg.start, seg.end),
Bucket::Duplicate => println!("Dup: {}..{}", seg.start, seg.end),
Bucket::Random => println!("Rand: {}..{}", seg.start, seg.end),
}
}
})).unwrap();
# Benchmark example
$ dd if=/dev/ublkb0 of=/dev/null bs=16M
256+0 records in
256+0 records out
4294967296 bytes (4.3 GB, 4.0 GiB) copied, 1.186 s, 3.6 GB/s
CONFIG_BLK_DEV_UBLK enabledUBLK_F_UNPRIVILEGED_DEV support in kernelCheck if ublk is available:
# Check if ublk module is loaded
lsmod | grep ublk
# Load if needed
sudo modprobe ublk_drv
test-bd add [OPTIONS]
Options:
--id <ID> Device ID [default: 0, -1 for auto]
-s, --size <SIZE> Size [default: "1 GiB"]
-f, --fill <FILL> Percent fill data [default: 25]
-d, --duplicate <DUP> Percent duplicate data [default: 50]
-r, --random <RANDOM> Percent random data [default: 25]
--seed <SEED> Seed (0 = random) [default: 0]
--segments <SEGMENTS> Number of segments [default: 100]
--privileged Run in privileged mode
-J, --json Output device info as JSON
test-bd del --id <ID>
Export device configuration and segment information:
$ test-bd add --id 0 --size 1G --segments 3 -J --seed 12345
{
"seed": 12345,
"device_id": 0,
"segments": [
{
"start": 0,
"end": 32455089,
"pattern": "Random"
},
{
"start": 32455089,
"end": 395484167,
"pattern": "Duplicate"
},
{
"start": 395484167,
"end": 1000000000,
"pattern": "Random"
}
]
}
See the examples directory:
# Run the simple example
cargo run --example simple
# Build
cargo build --release
# Run tests
cargo test
# Build documentation
cargo doc --open
# For local development with path dependency:
# Uncomment the libublk path dependency in Cargo.toml
Contributions are welcome! Please feel free to submit a Pull Request.
Licensed under either of:
at your option.
Based on the libublk-rs example ramdisk target