use std::process::{Command, Stdio};
use std::thread;
use std::time::{Duration, Instant};
fn simulate_long_operation(duration_ms: u64) -> Result<(), String> {
thread::sleep(Duration::from_millis(duration_ms));
Ok(())
}
fn operation_with_timeout<F>(operation: F, timeout: Duration) -> Result<(), String>
where
F: FnOnce() -> Result<(), String> + Send + 'static,
{
use std::sync::mpsc;
let (tx, rx) = mpsc::channel();
thread::spawn(move || {
let result = operation();
let _ = tx.send(result);
});
match rx.recv_timeout(timeout) {
Ok(result) => result,
Err(_) => Err("Operation timed out".to_string()),
}
}
#[test]
fn test_operation_completes_within_timeout() {
let result =
operation_with_timeout(|| simulate_long_operation(100), Duration::from_millis(500));
assert!(result.is_ok(), "Operation should complete within timeout");
}
#[test]
fn test_operation_exceeds_timeout() {
let result =
operation_with_timeout(|| simulate_long_operation(500), Duration::from_millis(100));
assert!(result.is_err(), "Operation should timeout");
assert_eq!(result.unwrap_err(), "Operation timed out");
}
#[test]
fn test_timeout_boundary_just_under() {
let timeout_ms = 500;
let operation_ms = 100;
let start = Instant::now();
let result = operation_with_timeout(
move || simulate_long_operation(operation_ms),
Duration::from_millis(timeout_ms),
);
let elapsed = start.elapsed();
assert!(
result.is_ok(),
"Operation just under timeout should succeed (elapsed: {:?})",
elapsed
);
assert!(
elapsed < Duration::from_millis(timeout_ms * 2),
"Should complete within reasonable time (elapsed: {:?})",
elapsed
);
}
#[test]
fn test_timeout_boundary_just_over() {
let timeout_ms = 100;
let operation_ms = 300;
let start = Instant::now();
let result = operation_with_timeout(
move || simulate_long_operation(operation_ms),
Duration::from_millis(timeout_ms),
);
let elapsed = start.elapsed();
assert!(
result.is_err(),
"Operation just over timeout should fail (elapsed: {:?})",
elapsed
);
assert!(
elapsed >= Duration::from_millis(timeout_ms),
"Should wait at least timeout duration (elapsed: {:?})",
elapsed
);
assert!(
elapsed < Duration::from_millis(timeout_ms + 500),
"Should timeout promptly (elapsed: {:?}, expected: ~{}ms)",
elapsed,
timeout_ms
);
}
#[test]
fn test_timeout_error_message_clarity() {
let result =
operation_with_timeout(|| simulate_long_operation(500), Duration::from_millis(100));
assert!(result.is_err());
let error = result.unwrap_err();
assert!(
error.contains("timeout") || error.contains("timed out"),
"Error message should mention timeout: {}",
error
);
assert!(!error.is_empty(), "Error message should not be empty");
}
#[test]
fn test_multiple_timeouts_sequential() {
let results: Vec<Result<(), String>> = vec![
operation_with_timeout(|| simulate_long_operation(50), Duration::from_millis(500)),
operation_with_timeout(|| simulate_long_operation(1000), Duration::from_millis(300)),
operation_with_timeout(|| simulate_long_operation(50), Duration::from_millis(500)),
];
assert!(
results[0].is_ok(),
"First operation should succeed (50ms with 500ms timeout)"
);
assert!(
results[1].is_err(),
"Second operation should timeout (1000ms with 300ms timeout)"
);
assert!(
results[2].is_ok(),
"Third operation should succeed (50ms with 500ms timeout)"
);
}
#[test]
fn test_cargo_bloat_timeout_simulation() {
let start = Instant::now();
let result = Command::new("sleep")
.arg("0.1")
.stdout(Stdio::null())
.stderr(Stdio::null())
.spawn();
match result {
Ok(mut child) => {
thread::sleep(Duration::from_millis(50));
match child.try_wait() {
Ok(Some(_status)) => {
assert!(
start.elapsed() < Duration::from_secs(1),
"Process should complete quickly"
);
}
Ok(None) => {
let _ = child.kill();
}
Err(_) => {
let _ = child.kill();
}
}
}
Err(_) => {
}
}
}
#[test]
fn test_timeout_cleanup_no_orphaned_resources() {
use std::sync::{
atomic::{AtomicBool, Ordering},
Arc,
};
let cleanup_called = Arc::new(AtomicBool::new(false));
let cleanup_called_clone = cleanup_called.clone();
let _result = operation_with_timeout(
move || {
simulate_long_operation(500)?;
cleanup_called_clone.store(true, Ordering::SeqCst);
Ok(())
},
Duration::from_millis(100),
);
thread::sleep(Duration::from_millis(150));
}
#[test]
fn test_timeout_with_zero_duration() {
let result = operation_with_timeout(|| simulate_long_operation(50), Duration::from_millis(0));
assert!(result.is_err(), "Zero timeout should immediately fail");
}
#[test]
fn test_timeout_with_very_large_duration() {
let result = operation_with_timeout(
|| simulate_long_operation(10),
Duration::from_secs(3600), );
assert!(
result.is_ok(),
"Operation should complete before large timeout"
);
}
#[test]
fn test_timeout_accuracy_within_tolerance() {
let timeout_ms = 200;
let tolerance_ms = 500;
let start = Instant::now();
let result = operation_with_timeout(
|| simulate_long_operation(1000), Duration::from_millis(timeout_ms),
);
let elapsed = start.elapsed().as_millis();
assert!(result.is_err(), "Should timeout");
assert!(
elapsed >= timeout_ms as u128,
"Timeout should fire after timeout duration"
);
assert!(
elapsed < (timeout_ms + tolerance_ms) as u128,
"Timeout should fire within tolerance ({}ms), was {}ms",
tolerance_ms,
elapsed
);
}