use super::super::{AdvanceLauncher, Launcher};
use std::io;
use std::os::unix::fs::PermissionsExt;
use std::path::Path;
use tempfile::TempDir;
#[test]
fn advance_launcher_spawns_detached_and_returns_at_once() {
let ws = TempDir::new().unwrap();
let launcher = AdvanceLauncher::with_exe("true".into());
launcher.launch(ws.path(), "a1").unwrap();
assert!(
driver_log_path(ws.path(), "a1").is_file(),
"the launch opens the driver's stderr sink under steps/ (§2.11)"
);
}
#[test]
fn advance_launcher_captures_child_stderr_and_appends_across_launches() {
let ws = TempDir::new().unwrap();
let exe = ws.path().join("stub-driver");
std::fs::write(&exe, "#!/bin/sh\necho declined >&2\n").unwrap();
std::fs::set_permissions(&exe, std::fs::Permissions::from_mode(0o755)).unwrap();
let launcher = AdvanceLauncher::with_exe(exe);
launcher.launch(ws.path(), "a1").unwrap();
assert_eq!(
declines_until(ws.path(), "a1", 1),
1,
"the first is captured"
);
launcher.launch(ws.path(), "a1").unwrap();
assert_eq!(
declines_until(ws.path(), "a1", 2),
2,
"the second appends; nothing truncates the first"
);
}
fn declines_until(workspace: &Path, agent_id: &str, want: usize) -> usize {
declines_within(workspace, agent_id, want, 600)
}
fn declines_within(workspace: &Path, agent_id: &str, want: usize, retries: u32) -> usize {
let path = driver_log_path(workspace, agent_id);
let mut seen = 0;
for attempt in 0..retries {
if attempt > 0 {
std::thread::sleep(std::time::Duration::from_millis(5));
}
seen = std::fs::read_to_string(&path)
.map(|s| s.matches("declined").count())
.unwrap_or(0);
if seen >= want {
break;
}
}
seen
}
#[test]
fn declines_within_gives_up_when_the_count_never_arrives() {
let ws = TempDir::new().unwrap();
assert_eq!(declines_within(ws.path(), "a1", 1, 2), 0);
}
#[test]
fn advance_launcher_declines_when_the_stderr_sink_cannot_be_opened() {
let ws = TempDir::new().unwrap();
std::fs::write(ws.path().join(crate::prompt::step::STEPS_DIR), b"not a dir").unwrap();
let launcher = AdvanceLauncher::with_exe("true".into());
let err = launcher.launch(ws.path(), "a1").unwrap_err();
assert_eq!(err.kind(), io::ErrorKind::NotADirectory);
}
fn driver_log_path(workspace: &Path, agent_id: &str) -> std::path::PathBuf {
workspace
.join(crate::prompt::step::STEPS_DIR)
.join(agent_id)
.join(crate::prompt::step::DRIVER_LOG_FILE)
}
#[test]
fn detach_into_own_session_never_fails() {
super::super::launch::detach_into_own_session().unwrap();
super::super::launch::detach_into_own_session().unwrap();
}
#[test]
fn advance_launcher_surfaces_a_spawn_failure() {
let ws = TempDir::new().unwrap();
let launcher = AdvanceLauncher::with_exe("/no/such/litany-binary".into());
let err = launcher.launch(ws.path(), "a1").unwrap_err();
assert_eq!(err.kind(), io::ErrorKind::NotFound);
}