#![allow(
clippy::unwrap_used,
clippy::expect_used,
clippy::panic,
clippy::indexing_slicing,
reason = "test code"
)]
use std::process::Command;
use kernel::{Address, RunId};
use runtime::{Backlog, Started};
const RUN: RunId = RunId::CITY;
#[expect(clippy::disallowed_methods, reason = "test fixture (child D4)")]
fn never_ends() -> Command {
let mut command = if cfg!(windows) {
let mut command = Command::new("ping");
command.args(["-n", "100000", "127.0.0.1"]);
command
} else {
let mut command = Command::new("sleep");
command.arg("100000");
command
};
command.current_dir(std::env::temp_dir());
command
}
#[expect(clippy::disallowed_methods, reason = "test fixture (child D4)")]
fn finishes_now(code: i32) -> Command {
let mut command = if cfg!(windows) {
let mut command = Command::new("cmd");
command.args(["/C", &format!("exit {code}")]);
command
} else {
let mut command = Command::new("sh");
command.args(["-c", &format!("exit {code}")]);
command
};
command.current_dir(std::env::temp_dir());
command
}
#[test]
fn a_command_that_finishes_inside_the_window_produces_no_handle() {
let backlog = Backlog::new();
let addr = Address::parse("lab/room1").unwrap();
let started = backlog
.run(RUN, &addr, "exit 3".to_owned(), finishes_now(3))
.unwrap();
match started {
Started::Settled { exit, .. } => {
assert_eq!(exit, runtime::Exit::Ended { code: 3 });
}
Started::Backgrounded { .. } => panic!("a short command must still feel synchronous"),
}
assert!(
backlog.standing(&addr).unwrap().is_empty(),
"nothing is left in the table"
);
assert!(backlog.harvest(RUN).unwrap().is_empty());
}
#[test]
fn halt_terminates_a_command_that_never_ends_and_the_run_returns_to_a_boundary() {
let backlog = Backlog::new();
let addr = Address::parse("lab/room1").unwrap();
let stopper = backlog.clone();
let building = Address::parse("lab").unwrap();
let brake = std::thread::spawn(move || {
std::thread::sleep(std::time::Duration::from_millis(300));
stopper.halt(Some(&building)).unwrap()
});
let started = backlog
.run(RUN, &addr, "ping forever".to_owned(), never_ends())
.unwrap();
let reached = brake.join().unwrap();
assert_eq!(reached, 1, "halt reached the member");
assert!(
matches!(started, Started::Settled { .. }),
"the call came back to a boundary instead of staying in a system call"
);
assert!(backlog.standing(&addr).unwrap().is_empty());
}
#[test]
fn a_command_that_outlives_the_window_keeps_running_where_halt_can_reach_it() {
let backlog = Backlog::with_window(runtime::PollBudget::new(1, 1));
let addr = Address::parse("lab/room1").unwrap();
let started = backlog
.run(RUN, &addr, "ping forever".to_owned(), never_ends())
.unwrap();
let id = match started {
Started::Backgrounded { id, .. } => id,
Started::Settled { .. } => panic!("a command that never ends cannot have settled"),
};
let standing = backlog.standing(&addr).unwrap();
assert_eq!(standing.len(), 1);
assert_eq!(standing[0].id, id);
assert!(
backlog.harvest(RUN).unwrap().is_empty(),
"nothing is reported before it stops"
);
assert_eq!(backlog.halt(None).unwrap(), 1);
let mut collected = Vec::new();
for _ in 0..100 {
collected = backlog.harvest(RUN).unwrap();
if !collected.is_empty() {
break;
}
std::thread::sleep(std::time::Duration::from_millis(20));
}
assert_eq!(collected.len(), 1, "the stopped member is reported once");
assert_eq!(collected[0].id, id);
assert!(backlog.harvest(RUN).unwrap().is_empty());
assert!(backlog.standing(&addr).unwrap().is_empty());
}
#[test]
#[expect(clippy::disallowed_methods, reason = "test fixture (child D4)")]
fn a_released_command_is_let_go_without_reaching_another_run() {
let backlog = Backlog::with_window(runtime::PollBudget::new(1, 1));
let addr = Address::parse("vault/room1").unwrap();
let (ended, other) = (RunId::from_bytes([1; 16]), RunId::from_bytes([2; 16]));
let mut slow = if cfg!(windows) {
let mut command = Command::new("ping");
command.args(["-n", "2", "127.0.0.1"]);
command
} else {
let mut command = Command::new("sleep");
command.arg("1");
command
};
slow.current_dir(std::env::temp_dir());
let started = backlog.run(ended, &addr, "slow".to_owned(), slow).unwrap();
assert!(matches!(started, Started::Backgrounded { .. }));
assert_eq!(backlog.release(ended), 1);
for _ in 0..500 {
assert!(backlog.harvest(other).unwrap().is_empty());
if backlog.standing(&addr).unwrap().is_empty() {
return;
}
std::thread::sleep(std::time::Duration::from_millis(20));
}
panic!("a released command that stopped is still in the table");
}