#[allow(unused_imports)]
use safer_ring::{Batch, BatchConfig, Operation, PinnedBuffer, Ring};
#[allow(unused_imports)]
use std::pin::Pin;
#[allow(unused_imports)]
fn should_skip_io_uring_tests() -> bool {
cfg!(not(target_os = "linux"))
}
#[tokio::test]
async fn test_empty_batch_error() {
if should_skip_io_uring_tests() {
println!("Skipping io_uring test on non-Linux platform (macOS/Windows) - io_uring requires Linux kernel 5.1+");
return;
}
async fn test_with_ring(ring: &mut Ring<'_>) -> Result<(), Box<dyn std::error::Error>> {
let batch = Batch::new();
let result = ring.submit_batch_standalone(batch);
assert!(result.is_err(), "Empty batch should return an error");
println!("✓ Empty batch correctly returned error");
Ok(())
}
let mut ring = Ring::new(32).expect("Failed to create ring");
test_with_ring(&mut ring).await.unwrap();
}
#[tokio::test]
async fn test_single_operation_batch() {
if should_skip_io_uring_tests() {
println!("Skipping io_uring test on non-Linux platform (macOS/Windows) - io_uring requires Linux kernel 5.1+");
return;
}
let mut buffer = PinnedBuffer::with_capacity(1024);
let mut ring = match Ring::new(32) {
Ok(r) => r,
Err(e) => {
println!("Could not create ring (io_uring may not be available): {e}");
return;
}
};
let mut batch = Batch::new();
if let Err(e) = batch.add_operation(Operation::read().fd(0).buffer(buffer.as_mut_slice())) {
println!("Could not add operation to batch: {e}");
return;
}
let mut batch_future = match ring.submit_batch_standalone(batch) {
Ok(f) => f,
Err(e) => {
println!("Could not submit batch: {e}");
return;
}
};
let _result = std::future::poll_fn(|cx| batch_future.poll_with_ring(&mut ring, cx)).await;
#[cfg(not(target_os = "linux"))]
{
if let Ok(batch_result) = _result {
assert_eq!(batch_result.results.len(), 1);
println!("✓ Single operation batch completed successfully");
} else {
println!("Batch failed as expected on non-Linux platform");
}
}
#[cfg(target_os = "linux")]
{
println!("✓ Single operation batch submitted and polled successfully on Linux");
}
}
#[tokio::test]
async fn test_multiple_operations_batch() {
if should_skip_io_uring_tests() {
println!("Skipping io_uring test on non-Linux platform (macOS/Windows) - io_uring requires Linux kernel 5.1+");
return;
}
let mut buffer1 = PinnedBuffer::with_capacity(512);
let mut buffer2 = PinnedBuffer::with_capacity(512);
let mut ring = match Ring::new(32) {
Ok(r) => r,
Err(e) => {
println!("Could not create ring (io_uring may not be available): {e}");
return;
}
};
let mut batch = Batch::new();
if let Err(e) = batch.add_operation(Operation::read().fd(0).buffer(buffer1.as_mut_slice())) {
println!("Could not add first operation to batch: {e}");
return;
}
if let Err(e) = batch.add_operation(Operation::read().fd(0).buffer(buffer2.as_mut_slice())) {
println!("Could not add second operation to batch: {e}");
return;
}
let mut batch_future = match ring.submit_batch_standalone(batch) {
Ok(f) => f,
Err(e) => {
println!("Could not submit batch: {e}");
return;
}
};
let _result = std::future::poll_fn(|cx| batch_future.poll_with_ring(&mut ring, cx)).await;
#[cfg(not(target_os = "linux"))]
{
if let Ok(batch_result) = _result {
assert_eq!(batch_result.results.len(), 2);
println!("✓ Multiple operations batch completed successfully");
} else {
println!("Batch failed as expected on non-Linux platform");
}
}
#[cfg(target_os = "linux")]
{
println!("✓ Multiple operations batch submitted and polled successfully on Linux");
}
}
#[tokio::test]
async fn test_batch_with_dependencies() {
if should_skip_io_uring_tests() {
println!("Skipping io_uring test on non-Linux platform (macOS/Windows) - io_uring requires Linux kernel 5.1+");
return;
}
let test_future = async {
let mut buffer1 = PinnedBuffer::with_capacity(512);
let mut buffer2 = PinnedBuffer::with_capacity(512);
let mut ring = Ring::new(32)?;
let mut batch = Batch::new();
let op1 = Operation::read().fd(0).buffer(buffer1.as_mut_slice());
let op2 = Operation::read().fd(0).buffer(buffer2.as_mut_slice());
let idx1 = batch.add_operation(op1)?;
let idx2 = batch.add_operation(op2)?;
batch.add_dependency(idx2, idx1)?;
let mut batch_future = ring.submit_batch_standalone(batch)?;
let result = std::future::poll_fn(|cx| batch_future.poll_with_ring(&mut ring, cx)).await;
#[cfg(not(target_os = "linux"))]
{
let batch_result = result?;
assert_eq!(batch_result.results.len(), 2);
}
#[cfg(target_os = "linux")]
{
let _result = result;
}
Ok::<(), Box<dyn std::error::Error>>(())
};
let _ = Box::pin(test_future).await;
}
#[tokio::test]
async fn test_batch_with_config() {
if should_skip_io_uring_tests() {
println!("Skipping io_uring test on non-Linux platform (macOS/Windows) - io_uring requires Linux kernel 5.1+");
return;
}
let test_future = async {
let mut buffer = PinnedBuffer::with_capacity(1024);
let mut ring = Ring::new(32)?;
let mut batch = Batch::new();
let operation = Operation::read().fd(-1).buffer(buffer.as_mut_slice());
batch.add_operation(operation)?;
let config = BatchConfig {
fail_fast: true,
max_batch_size: 10,
enforce_dependencies: false,
};
let mut batch_future = ring.submit_batch_standalone_with_config(batch, config)?;
let result = std::future::poll_fn(|cx| batch_future.poll_with_ring(&mut ring, cx)).await;
#[cfg(not(target_os = "linux"))]
{
let batch_result = result?;
assert_eq!(batch_result.results.len(), 1);
}
#[cfg(target_os = "linux")]
{
let _result = result;
}
Ok::<(), Box<dyn std::error::Error>>(())
};
let _ = Box::pin(test_future).await;
}
#[tokio::test]
async fn test_batch_error_conditions() {
if should_skip_io_uring_tests() {
println!("Skipping io_uring test on non-Linux platform (macOS/Windows) - io_uring requires Linux kernel 5.1+");
return;
}
let test_future = async {
let mut buffer1 = PinnedBuffer::with_capacity(512);
let mut buffer2 = PinnedBuffer::with_capacity(512);
let _ring = Ring::new(32)?;
let op1 = Operation::read().fd(0).buffer(buffer1.as_mut_slice());
let op2 = Operation::read().fd(0).buffer(buffer2.as_mut_slice());
let mut batch = Batch::new();
let idx1 = batch.add_operation(op1)?;
let idx2 = batch.add_operation(op2)?;
batch.add_dependency(idx1, idx2)?;
let result = batch.add_dependency(idx2, idx1);
assert!(result.is_err());
drop(batch);
Ok::<(), Box<dyn std::error::Error>>(())
};
let _ = Box::pin(test_future).await;
}
#[tokio::test]
async fn test_large_batch() {
if should_skip_io_uring_tests() {
println!("Skipping io_uring test on non-Linux platform (macOS/Windows) - io_uring requires Linux kernel 5.1+");
return;
}
let mut buf1 = PinnedBuffer::with_capacity(64);
let mut buf2 = PinnedBuffer::with_capacity(64);
let mut buf3 = PinnedBuffer::with_capacity(64);
let mut ring = match Ring::new(256) {
Ok(r) => r,
Err(e) => {
println!("Could not create ring (io_uring may not be available): {e}");
return;
}
};
let mut batch = Batch::new();
if let Err(e) = batch.add_operation(Operation::read().fd(0).buffer(buf1.as_mut_slice())) {
println!("Could not add first operation: {e}");
return;
}
if let Err(e) = batch.add_operation(Operation::read().fd(0).buffer(buf2.as_mut_slice())) {
println!("Could not add second operation: {e}");
return;
}
if let Err(e) = batch.add_operation(Operation::read().fd(0).buffer(buf3.as_mut_slice())) {
println!("Could not add third operation: {e}");
return;
}
assert_eq!(batch.len(), 3);
let mut batch_future = match ring.submit_batch_standalone(batch) {
Ok(f) => f,
Err(e) => {
println!("Could not submit large batch: {e}");
return;
}
};
let _result = std::future::poll_fn(|cx| batch_future.poll_with_ring(&mut ring, cx)).await;
#[cfg(not(target_os = "linux"))]
{
if let Ok(batch_result) = _result {
assert_eq!(batch_result.results.len(), 3);
println!("✓ Large batch completed successfully");
} else {
println!("Large batch failed as expected on non-Linux platform");
}
}
#[cfg(target_os = "linux")]
{
println!("✓ Large batch submitted and polled successfully on Linux");
}
}