use super::super::held::Held;
use super::super::hold::{Ending, hold};
use super::{
advertised, aside, echo, entry_at, flapping_at, gesture, ops, receipt, refusal, row, set, work,
};
use crate::channel::Channel;
use crate::channel::material::read_dir;
use crate::config::Local;
use crate::invocation::{Capture, Invocation};
use crate::test_support::{Scratch, Waits};
use std::path::Path;
use std::sync::atomic::{AtomicUsize, Ordering};
static RUNS: AtomicUsize = AtomicUsize::new(0);
fn counted(set: &[Local], invocation: &Invocation) -> Capture {
RUNS.fetch_add(1, Ordering::Relaxed);
echo(set, invocation)
}
fn channel_at(dir: &Path) -> Channel {
let material = read_dir(dir).expect("readable").expect("provisioned");
Channel::open(&material).expect("opened")
}
#[test]
fn a_swallowed_capture_is_posted_first_on_the_next_dial() {
let scratch = Scratch::new();
let engine = flapping_at(
scratch.path(),
vec![
Some(advertised()),
Some(work(vec![row("i-1", "Bash")])),
None,
Some(advertised()),
Some(receipt("i-1")),
Some(refusal(
"client \"foot-1\" already holds a read on this engine",
)),
Some(refusal("stop")),
],
);
let (waits, pause) = Waits::new();
assert_eq!(
crate::run::redial::redial(&entry_at(scratch.path()), &set(), counted, &aside(), &pause),
"stop"
);
assert_eq!(
ops(&engine),
[
"advertise",
"invocations",
"complete",
"advertise",
"complete",
"invocations",
"advertise"
],
"the re-post is the second channel's first act after its advertisement"
);
assert_eq!(
gesture(&engine, 4),
serde_json::json!({"op": "complete", "invocation": "i-1",
"capture": {"stdout": "Bash", "stderr": "1 tools", "exit_code": 0}}),
"it carries the capture the first channel computed, verbatim"
);
assert_eq!(
RUNS.load(Ordering::Relaxed),
1,
"the hand-off ran once: the lease re-ran nothing"
);
assert_eq!(waits.heard().len(), 2, "one drop and one predecessor");
}
#[test]
fn a_refused_re_post_is_dropped_and_the_channel_reads_on() {
let scratch = Scratch::new();
let engine = flapping_at(
scratch.path(),
vec![
Some(advertised()),
Some(work(vec![row("i-1", "Bash")])),
None,
Some(advertised()),
Some(refusal("no invocation \"i-1\" is in flight")),
Some(work(vec![])),
Some(refusal(
"client \"foot-1\" already holds a read on this engine",
)),
Some(refusal("stop")),
],
);
let (_waits, pause) = Waits::new();
assert_eq!(
crate::run::redial::redial(&entry_at(scratch.path()), &set(), echo, &aside(), &pause),
"stop",
"the refusal ended nothing: the channel ran on to its own ending"
);
assert_eq!(
ops(&engine),
[
"advertise",
"invocations",
"complete",
"advertise",
"complete",
"invocations",
"invocations",
"advertise"
],
"it read on, and the refused capture was not posted again"
);
}
#[test]
fn a_re_post_the_wire_swallowed_again_is_still_held() {
let scratch = Scratch::new();
let _engine = flapping_at(
scratch.path(),
vec![
Some(advertised()),
Some(work(vec![row("i-1", "Bash")])),
None,
Some(advertised()),
None,
Some(advertised()),
Some(receipt("i-1")),
Some(refusal(
"client \"foot-1\" already holds a read on this engine",
)),
],
);
let channel = channel_at(scratch.path());
let Ending::Again { held, .. } = hold(&channel, &set(), echo, &aside(), None) else {
panic!("a dropped completion must be worth another dial");
};
let carried = held.expect("the capture the wire swallowed");
let Ending::Again { held, .. } = hold(&channel, &set(), echo, &aside(), Some(carried)) else {
panic!("a dropped re-post must be worth another dial");
};
let carried = held.expect("a wire failure is not an answer");
assert_eq!(
carried,
Held {
id: "i-1".to_owned(),
capture: Capture {
stdout: "Bash".to_owned(),
stderr: "1 tools".to_owned(),
exit_code: 0,
},
},
"the same capture, unchanged by a second drop"
);
let Ending::Again { held, .. } = hold(&channel, &set(), echo, &aside(), Some(carried)) else {
panic!("the refused read is this box's own predecessor");
};
assert!(
held.is_none(),
"a capture the engine has answered for is let go"
);
}