use super::*;
#[test]
fn validates_execution_preflight_receipts() {
let plan = subtree_plan();
plan.validate_execution_preflight_receipts(
&topology_receipt(&plan),
&quiescence_receipt(&plan),
PREFLIGHT_ID,
AS_OF,
)
.expect("valid execution preflights");
}
#[test]
fn applies_execution_preflight_receipt_bundle() {
let mut plan = subtree_plan();
plan.targets[0].control_authority =
ControlAuthority::root_controller(AuthorityEvidence::Declared);
plan.targets[0].snapshot_read_authority =
SnapshotReadAuthority::root_configured_read(AuthorityEvidence::Declared);
let receipts = execution_preflight_receipts(&subtree_plan());
plan.apply_execution_preflight_receipts(&receipts, AS_OF)
.expect("apply execution preflight bundle");
assert_eq!(plan.targets[0].control_authority, proven_root_control());
assert_eq!(plan.targets[0].snapshot_read_authority, proven_root_read());
plan.validate_for_execution()
.expect("bundle makes plan executable");
}
#[test]
fn rejects_expired_execution_preflight_bundle() {
let mut plan = subtree_plan();
let receipts = execution_preflight_receipts(&plan);
let err = plan
.apply_execution_preflight_receipts(&receipts, "unix:250")
.expect_err("expired preflight bundle rejects");
std::assert_matches!(
err,
BackupPlanError::PreflightReceiptExpired { preflight_id, expires_at, as_of }
if preflight_id == PREFLIGHT_ID && expires_at == EXPIRES_AT && as_of == "unix:250"
);
}
#[test]
fn rejects_mismatched_preflight_id_in_bundle_receipts() {
let mut plan = subtree_plan();
let mut receipts = execution_preflight_receipts(&plan);
receipts.topology.preflight_id = "preflight-other".to_string();
let err = plan
.apply_execution_preflight_receipts(&receipts, AS_OF)
.expect_err("mismatched preflight receipt rejects");
std::assert_matches!(
err,
BackupPlanError::PreflightReceiptIdMismatch { expected, actual }
if expected == PREFLIGHT_ID && actual == "preflight-other"
);
}
#[test]
fn rejects_topology_preflight_hash_drift() {
let plan = subtree_plan();
let mut receipt = topology_receipt(&plan);
receipt.topology_hash_at_preflight =
"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff".to_string();
let err = plan
.validate_execution_preflight_receipts(
&receipt,
&quiescence_receipt(&plan),
PREFLIGHT_ID,
AS_OF,
)
.expect_err("topology drift rejects");
std::assert_matches!(
err,
BackupPlanError::TopologyPreflightHashMismatch { expected, actual }
if expected == plan.topology_hash_before_quiesce
&& actual == "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
);
}
#[test]
fn rejects_unaccepted_quiescence_preflight() {
let plan = subtree_plan();
let mut receipt = quiescence_receipt(&plan);
receipt.accepted = false;
let err = plan
.validate_execution_preflight_receipts(
&topology_receipt(&plan),
&receipt,
PREFLIGHT_ID,
AS_OF,
)
.expect_err("quiescence rejection rejects");
std::assert_matches!(err, BackupPlanError::QuiescencePreflightRejected);
}
#[test]
fn rejects_quiescence_target_mismatch() {
let plan = subtree_plan();
let mut receipt = quiescence_receipt(&plan);
receipt.targets.clear();
let err = plan
.validate_execution_preflight_receipts(
&topology_receipt(&plan),
&receipt,
PREFLIGHT_ID,
AS_OF,
)
.expect_err("quiescence target mismatch rejects");
std::assert_matches!(err, BackupPlanError::QuiescencePreflightTargetsMismatch);
}