ic-backup 0.63.0

Host-side snapshot backup and same-release recovery for Internet Computer canisters
Documentation
use crate::{
    model::{
        attempt_journal::MAX_OPERATION_ATTEMPTS,
        ic_mutation::{IcMutationAcknowledgement, IcMutationRequest, MAX_IC_MUTATION_REPLY_BYTES},
        ic_request::IcManagementMethodRecord,
        ic_snapshot_data::MAX_IC_SNAPSHOT_DATA_REPLY_BYTES,
        ic_snapshot_transfer_read::IcSnapshotTransferReadResponse,
        ic_update_response::IcUpdateResponseError,
    },
    tests::support::ic_mutation::{input, original},
};

#[test]
fn shared_fields_keep_distinct_lane_limits_order_and_redaction() {
    let original = original(IcManagementMethodRecord::StopCanister);
    let request =
        IcMutationRequest::new(&original.plan, 7, &original.journal, &original.payload).unwrap();
    let mut fields = input(&request);
    fields.target = fields.target.to_ascii_uppercase();
    fields.mutation_attempt = MAX_OPERATION_ATTEMPTS;
    fields.reply = vec![b'X'; MAX_IC_MUTATION_REPLY_BYTES];
    let mutation = IcMutationAcknowledgement::new(fields.clone()).unwrap();
    assert_eq!(mutation.input().target, original.payload.target());
    assert_eq!(mutation.input().reply, fields.reply);
    assert!(!format!("{mutation:?}").contains("XXXX"));
    fields.reply.push(b'X');
    assert_eq!(
        IcMutationAcknowledgement::new(fields.clone()).unwrap_err(),
        IcUpdateResponseError::ReplyTooLarge
    );
    let transfer = IcSnapshotTransferReadResponse::new(fields.clone()).unwrap();
    assert_eq!(transfer.input().target, original.payload.target());
    assert_eq!(transfer.input().reply, fields.reply);
    assert!(!format!("{transfer:?}").contains("XXXX"));
    fields.reply.resize(MAX_IC_SNAPSHOT_DATA_REPLY_BYTES, b'X');
    assert!(IcSnapshotTransferReadResponse::new(fields.clone()).is_ok());
    fields.reply.push(b'X');
    fields.target = "invalid principal".into();
    fields.mutation_attempt = 0;
    assert_eq!(
        IcMutationAcknowledgement::new(fields.clone()).unwrap_err(),
        IcUpdateResponseError::InvalidAttempt
    );
    assert!(matches!(
        IcSnapshotTransferReadResponse::new(fields.clone()),
        Err(IcUpdateResponseError::InvalidAttempt)
    ));
    fields.mutation_attempt = 1;
    assert_eq!(
        IcMutationAcknowledgement::new(fields.clone()).unwrap_err(),
        IcUpdateResponseError::ReplyTooLarge
    );
    assert!(matches!(
        IcSnapshotTransferReadResponse::new(fields.clone()),
        Err(IcUpdateResponseError::ReplyTooLarge)
    ));
    fields.reply.clear();
    assert_eq!(
        fields.admit(MAX_IC_MUTATION_REPLY_BYTES),
        Err(IcUpdateResponseError::InvalidTarget)
    );
    for attempt in [0, MAX_OPERATION_ATTEMPTS + 1] {
        fields.mutation_attempt = attempt;
        assert_eq!(
            fields.admit(MAX_IC_MUTATION_REPLY_BYTES),
            Err(IcUpdateResponseError::InvalidAttempt)
        );
    }
}