test: assert the deploy subtree's phase order and tail-on-failure
Two cases, both pinning the load-bearing property that the tail is reached on every path: a failed apply (AfterAny dep is terminal) and a failed verify (apply is cancel-cascaded, tail still claimable). Both assert the DAG rolls up to Failed — an Ok tail must not launder a failed deploy into a success.
This commit is contained in:
parent
816006fd48
commit
8499c793fe
1 changed files with 82 additions and 0 deletions
|
|
@ -926,6 +926,88 @@ fn cancelled_dag_finalizes_with_terminal_rollup() {
|
|||
);
|
||||
}
|
||||
|
||||
// ---- approval deploy subtree ----
|
||||
|
||||
/// The config-PR deploy is a subtree, not one opaque node. The
|
||||
/// resource-holding root completes immediately (its `Finishing` state is the
|
||||
/// parent gate that releases the children), then the phases run strictly in
|
||||
/// order — and the `AfterAny` tail still runs when the irreversible half fails,
|
||||
/// because it's the node that compensates for it.
|
||||
#[test]
|
||||
fn deploy_dag_runs_phases_in_order_and_tails_a_failed_apply() {
|
||||
let q = JobQueue::new(1);
|
||||
let id = submit(
|
||||
&q,
|
||||
templates::approval_deploy("agent-a", 7, "approval #7".to_owned()),
|
||||
);
|
||||
|
||||
let root = claim_one(&q);
|
||||
assert!(
|
||||
matches!(root.kind, NodeKind::DeployWindow { .. }),
|
||||
"root claims first: it holds the meta window for the whole subtree"
|
||||
);
|
||||
q.complete_node(id, root.node_id, Ok(()));
|
||||
|
||||
let verify = claim_one(&q);
|
||||
assert!(matches!(verify.kind, NodeKind::MergeVerify { .. }));
|
||||
q.complete_node(id, verify.node_id, Ok(()));
|
||||
|
||||
let apply = claim_one(&q);
|
||||
assert!(matches!(apply.kind, NodeKind::DeployApply { .. }));
|
||||
q.complete_node(
|
||||
id,
|
||||
apply.node_id,
|
||||
Err("nixos-container update blew up".into()),
|
||||
);
|
||||
|
||||
let tail = claim_one(&q);
|
||||
assert!(
|
||||
matches!(tail.kind, NodeKind::DeployTail { .. }),
|
||||
"AfterAny tail runs on a failed apply — that's the whole point of it"
|
||||
);
|
||||
q.complete_node(id, tail.node_id, Ok(()));
|
||||
|
||||
let summary = q.terminal_summary(id).expect("dag terminal");
|
||||
assert_eq!(
|
||||
summary.state,
|
||||
State::Failed,
|
||||
"an Ok tail must not launder a failed deploy into a success"
|
||||
);
|
||||
assert_eq!(summary.approval_id, Some(7));
|
||||
}
|
||||
|
||||
/// A pre-merge rejection (drift gate, eval failure) cancel-cascades the
|
||||
/// irreversible half via its `AfterOk` edge, but the tail is still reached —
|
||||
/// it owns the forge mirror, not just compensation.
|
||||
#[test]
|
||||
fn deploy_dag_skips_apply_but_still_runs_tail_when_verify_fails() {
|
||||
let q = JobQueue::new(1);
|
||||
let id = submit(
|
||||
&q,
|
||||
templates::approval_deploy("agent-a", 9, "approval #9".to_owned()),
|
||||
);
|
||||
|
||||
let root = claim_one(&q);
|
||||
q.complete_node(id, root.node_id, Ok(()));
|
||||
let verify = claim_one(&q);
|
||||
q.complete_node(
|
||||
id,
|
||||
verify.node_id,
|
||||
Err("PR head drifted since review".into()),
|
||||
);
|
||||
|
||||
let tail = claim_one(&q);
|
||||
assert!(
|
||||
matches!(tail.kind, NodeKind::DeployTail { .. }),
|
||||
"apply is cancel-cascaded, so the tail is the next claimable node"
|
||||
);
|
||||
q.complete_node(id, tail.node_id, Ok(()));
|
||||
|
||||
let summary = q.terminal_summary(id).expect("dag terminal");
|
||||
assert_eq!(summary.state, State::Failed);
|
||||
assert_eq!(summary.approval_id, Some(9));
|
||||
}
|
||||
|
||||
// ---- steps, build logs, history ----
|
||||
|
||||
#[test]
|
||||
|
|
|
|||
Loading…
Reference in a new issue