use std::time::Duration;
use evalbox_sandbox::{Executor, Plan, Status};
use crate::common::payload;
#[test]
#[ignore]
fn test_timeout_enforced() {
let start = std::time::Instant::now();
let output = Executor::run(Plan::new(["sleep", "60"]).timeout(Duration::from_millis(500)))
.expect("Executor should run");
let elapsed = start.elapsed();
assert!(!output.success(), "Should not succeed after timeout");
assert_eq!(output.status, Status::Timeout, "Status should be Timeout");
assert!(
elapsed < Duration::from_secs(2),
"Should timeout quickly, took {elapsed:?}"
);
}
#[test]
#[ignore]
fn test_infinite_loop_timeout() {
let output = Executor::run(
Plan::new(["sh", "-c", "while true; do :; done"]).timeout(Duration::from_millis(500)),
)
.expect("Executor should run");
assert!(!output.success(), "Infinite loop should be killed");
assert_eq!(output.status, Status::Timeout, "Status should be Timeout");
}
#[test]
#[ignore]
fn test_max_pids_enforced() {
let output = Executor::run(
Plan::new(["./payload"])
.executable("payload", payload("fork_bomb"))
.binary_path("./payload")
.max_pids(10)
.timeout(Duration::from_secs(5)),
)
.expect("Executor should run");
assert!(!output.success(), "Fork bomb should be limited");
let stdout = output.stdout_str();
assert!(
stdout.contains("limit reached") || output.exit_code != Some(0),
"Should hit fork limit"
);
}
#[test]
#[ignore]
fn test_output_limit_enforced() {
let output = Executor::run(
Plan::new(["sh", "-c", "yes | head -c 100000"]) .max_output(1024) .timeout(Duration::from_secs(10)),
)
.expect("Executor should run");
let total_output = output.stdout.len() + output.stderr.len();
assert!(
total_output <= 1024 * 4, "Output should be limited to ~1KB, got {total_output} bytes"
);
assert!(
output.status == Status::OutputLimitExceeded || total_output <= 1024,
"Output limit should be enforced. Got {} bytes, status: {:?}",
total_output,
output.status
);
}
#[test]
#[ignore]
fn test_memory_limit_set() {
let output = Executor::run(
Plan::new([
"sh",
"-c",
"ulimit -v 2>/dev/null || cat /proc/self/limits | grep -i 'address space'",
])
.memory(64 * 1024 * 1024) .timeout(Duration::from_secs(5)),
)
.expect("Executor should run");
let stdout = output.stdout_str();
let stderr = output.stderr_str();
assert!(
output.exit_code.is_some(),
"Should get exit code. stdout: {stdout}, stderr: {stderr}"
);
}
#[test]
#[ignore]
fn test_fd_limit_set() {
let output =
Executor::run(Plan::new(["sh", "-c", "ulimit -n"]).timeout(Duration::from_secs(5)))
.expect("Executor should run");
if output.success() {
let stdout = output.stdout_str();
let limit_str = stdout.trim();
if let Ok(limit) = limit_str.parse::<u64>() {
assert!(
limit < 1000000,
"FD limit should be reasonable, got {limit}"
);
}
}
}
#[test]
#[ignore]
fn test_cpu_intensive_timeout() {
let start = std::time::Instant::now();
let output = Executor::run(
Plan::new([
"sh",
"-c",
"i=0; while [ $i -lt 999999999 ]; do i=$((i+1)); done",
])
.timeout(Duration::from_millis(500)),
)
.expect("Executor should run");
let elapsed = start.elapsed();
assert_eq!(output.status, Status::Timeout);
assert!(
elapsed < Duration::from_secs(2),
"CPU work should be killed by timeout"
);
}