use bash_interop::rig::{Driving, ExitStatus};
use crate::{ENTRY, Keeping, behind, provisioned, report, script};
use bash_interop::scratch::{Scripts, bash};
#[tokio::test]
async fn a_line_cut_short_by_a_shell_that_left_ends_the_run() {
let scripts = Scripts::of(&[(
ENTRY,
r#"
BC_INSTR KEEP say REC first
( BC_INSTR KEEP say REC fork; printf '(never finished' >&"${__BC__FD[KEEP]}" )
sleep 5
"#,
)]);
let failure = Keeping
.run(
&bash(scripts.at(ENTRY)),
provisioned(&Keeping),
)
.await
.err()
.expect("the half-read line must be reported");
assert!(
failure.to_string().contains("never finished"),
"{failure}"
);
}
#[tokio::test]
async fn a_line_cut_short_at_the_end_is_reported_beside_the_subjects_status() {
let scripts = Scripts::of(&[(
ENTRY,
r#"
setsid bash -c 'BC_INSTR KEEP say REC outsider $BASHPID; printf "(never finished" >&"${__BC__FD[KEEP]}"; sleep 30' &
sleep 0.3
exit 3
"#,
)]);
let ran = Keeping
.run(
&bash(scripts.at(ENTRY)),
provisioned(&Keeping),
)
.await
.unwrap();
let outsider: i32 = behind(&ran.shells, "REC")[0][1].parse().unwrap();
let _ = unsafe { libc::kill(outsider, libc::SIGKILL) };
let failed = ran
.failed
.as_ref()
.expect("the half-read line must be reported");
assert!(
failed.to_string().contains("never finished"),
"{failed}"
);
assert_eq!(
ran.subject,
ExitStatus::Code(3),
"and the subject's own status survives it"
);
}
#[tokio::test]
async fn a_line_that_will_not_read_ends_the_run() {
let scripts = Scripts::of(&[(
ENTRY,
r#"
BC_INSTR KEEP say REC first
printf '(junk\n' >&"${__BC__FD[KEEP]}"
BC_INSTR KEEP say REC second
sleep 5
"#,
)]);
let failure = Keeping
.run(
&bash(scripts.at(ENTRY)),
provisioned(&Keeping),
)
.await
.err()
.expect("a line that will not read must end the run");
assert!(
failure.to_string().contains("(junk"),
"it quotes what it could not read: {failure}"
);
}
#[tokio::test]
async fn a_frame_the_protocol_did_not_write_ends_the_run() {
let scripts = Scripts::of(&[(
ENTRY,
r#"
BC_INSTR KEEP say REC first
printf 'nonsense\n' >"${__BC__DIR[KEEP]}/join"
sleep 5
"#,
)]);
let failure = Keeping
.run(
&bash(scripts.at(ENTRY)),
provisioned(&Keeping),
)
.await
.err()
.expect("a line that is not a frame must end the run");
assert!(
failure.to_string().contains("\"nonsense\" is not a frame"),
"{failure}"
);
}
#[tokio::test]
async fn a_fault_on_one_pipe_touches_no_other() {
let ran = script(
r#"
BC_INSTR KEEP say REC first
BC_INSTR KEEP say REC second
"#,
)
.await;
assert_eq!(
behind(&ran.shells, "REC"),
[["first"], ["second"]],
"{}",
report(&ran.shells)
);
}