ic-backup 0.63.1

Host-side snapshot backup and same-release recovery for Internet Computer canisters
Documentation
//! Exclusive integration fixture roots; failed journeys retain their evidence.

use std::path::PathBuf;

/// Reserve a fresh root before a public integration journey writes any children.
pub(crate) fn temp_root(prefix: &str) -> PathBuf {
    let parent = std::env::var_os("TMPDIR").map_or_else(
        || {
            let parent = PathBuf::from(env!("CARGO_MANIFEST_DIR"))
                .ancestors()
                .nth(2)
                .unwrap()
                .join("target/tmp");
            std::fs::create_dir_all(&parent).expect("create workspace fixture parent");
            parent
        },
        PathBuf::from,
    );
    let selected_temp = parent
        .canonicalize()
        .unwrap_or_else(|error| panic!("resolve integration fixture parent: {error}"));
    let root = ic_host_fs::testing::create_fixture_directory(&selected_temp, prefix)
        .unwrap_or_else(|error| panic!("reserve integration fixture {prefix}: {error}"));
    eprintln!(
        "Integration fixture retained until success: {}",
        root.display()
    );
    root
}

/// Publish a finite private JSON fixture; this is test setup, not product authority.
pub(crate) fn create_json_durable(
    path: &std::path::Path,
    value: &impl serde::Serialize,
) -> Result<(), Box<dyn std::error::Error>> {
    let mut writer = ic_host_artifacts::artifact::BoundedWriter::new(Vec::new(), 16 * 1024 * 1024);
    serde_json::to_writer_pretty(&mut writer, value)?;
    let bytes = writer.into_inner();
    ic_host_fs::durable::write_bytes(
        path,
        ic_host_fs::durable::WriteOptions {
            mode: ic_host_fs::durable::PublicationMode::CreateNew,
            permissions: 0o600,
        },
        &bytes,
    )?;
    Ok(())
}

/// One valid single-target declaration; corruption tests retain their explicit JSON inputs.
pub(crate) fn single_operation_plan(
    target: &str,
    sequence: u64,
    request: &str,
) -> ic_backup::model::operation_plan::OperationPlanRecord {
    use ic_backup::model::{
        attempt_journal::AttemptBudgetRecord,
        inventory::{InventoryRecord, InventoryTargetRecord, InventoryTargetRequest},
        operation_plan::{
            OperationPlanRecord, OperationPlanRequest, PlanBudgetRecord, PlanContextRecord,
            PlanContextRequest, PlannedOperationRecord, PlannedOperationRequest,
        },
    };
    OperationPlanRecord::new(OperationPlanRequest {
        context: PlanContextRecord::new(&PlanContextRequest {
            network: "ab".repeat(32),
            caller: "2vxsx-fae".into(),
            release: "cd".repeat(32),
        })
        .unwrap(),
        inventory: InventoryRecord::new(vec![
            InventoryTargetRecord::new(&InventoryTargetRequest {
                canister_id: target.into(),
                parent_canister_id: None,
                role: None,
                module_hash: None,
            })
            .unwrap(),
        ])
        .unwrap(),
        selected_targets: vec![target.into()],
        operations: vec![
            PlannedOperationRecord::new(PlannedOperationRequest {
                depends_on: vec![],
                operation_sequence: sequence,
                target: target.into(),
                request: request.into(),
                budget: AttemptBudgetRecord::new(1, 1).unwrap(),
            })
            .unwrap(),
        ],
        budget: PlanBudgetRecord::new(1, 1).unwrap(),
    })
    .unwrap()
}