ic-backup 0.63.2

Host-side snapshot backup and same-release recovery for Internet Computer canisters
Documentation
//! The shared receipt owner qualifies its complete refusal matrix once.
use super::*;
use crate::{
    model::artifacts::ArtifactChecksumRecord,
    tests::support::{
        execution_workflow::{assert_pending, child, prepare_stage, workflow},
        response_fault::ReceiptFault,
    },
};
use std::{cell::Cell, fs};

#[derive(Debug, thiserror::Error)]
enum Failure {
    #[error(transparent)]
    Journal(#[from] AttemptJournalError),
    #[error("receipt does not match the original Applied operation")]
    Receipt,
}

#[test]
fn changed_outcome_attempt_or_request_never_prepares_or_changes_original_spending() {
    for fault in [
        ReceiptFault::NotApplied,
        ReceiptFault::Attempt,
        ReceiptFault::Request,
    ] {
        let prepared = prepare_stage("ic-backup-receipt-refusal", &workflow(), 0, child(0));
        let stage = prepared.open();
        let sequence = 42;
        let authority = stage.plan().attempt_authority(sequence).unwrap();
        let mut journal = AttemptJournalGuard::open(stage.layout().unwrap(), &authority).unwrap();
        let attempt = journal
            .reserve_planned_mutation(&stage.plan().digest())
            .unwrap();
        let original = fs::read(journal.path()).unwrap();
        let request = ArtifactChecksumRecord::from_hash(authority.binding().request()).unwrap();
        let mut receipt = MutationReceiptRequest {
            attempt,
            request: request.clone(),
            outcome: MutationOutcomeRecord::Applied,
            evidence: ArtifactChecksumRecord::from_bytes(b"qualified original"),
        };
        fault.apply(&mut receipt, &"00".repeat(32));
        let prepared_calls = Cell::new(0);
        assert!(matches!(
            record_applied(
                &mut journal,
                receipt,
                attempt,
                request.hash(),
                Failure::Receipt,
                || {
                    prepared_calls.set(1);
                    Ok(())
                }
            ),
            Err(Failure::Receipt)
        ));
        assert_eq!(prepared_calls.get(), 0);
        assert_eq!(fs::read(journal.path()).unwrap(), original);
        drop(journal);
        assert_pending(&stage, sequence);
    }
}