canic-host 0.110.35

Host-side App build and desired-state Fleet reconciliation library for Canic workspaces
Documentation
use super::*;
use crate::{
    fleet_ensure::ops::{write_journal, write_plan},
    test_support::temp_dir,
};
use std::fs;

fn request(root: &Path) -> FleetReadinessRequest<'_> {
    FleetReadinessRequest {
        workspace: root,
        environment: "local",
        fleet: "fleet",
        icp_executable: "must-not-run",
        signing_identity: None,
        operator: Principal::management_canister(),
        cycles_ledger: Principal::management_canister(),
        estimated_required_cycles: None,
    }
}

#[test]
fn unknown_funding_is_not_claimed_sufficient_and_estimates_never_grant_authority() {
    let root = temp_dir("readiness-estimate");
    let mut request = request(&root);
    let unknown = report(&request, "network".into(), 10, None);
    assert!(unknown.estimated_shortfall_cycles.is_none());
    request.estimated_required_cycles = Some(11);
    let estimate = report(&request, "network".into(), 10, None);
    assert_eq!(estimate.estimated_shortfall_cycles, Some(1));
    assert_eq!(
        estimate.blockers,
        vec![ReadinessBlocker::EstimatedFundingShortfall]
    );
    assert!(!root.exists());
}

#[test]
fn retained_work_is_reported_without_rewriting_evidence_or_opening_a_lock() {
    let mut fixture = crate::fleet_ensure::tests::protocol_tranche_fixture(Vec::new());
    fixture.desired.fleet = "fleet".into();
    let root = fixture.root;
    let request = request(&root);
    let paths = EnsurePaths::under(&root, "local", "fleet");
    let mut plan = super::super::tests::estate_funding_plan();
    plan.reviewed_desired = Some(Box::new(
        crate::fleet_ensure::model::ReviewedDesiredFleetRecord::capture(&fixture.desired),
    ));
    crate::fleet_ensure::tests::retain_recorded_retirement(&mut plan, Vec::new());
    let (_, mut journal) = super::super::tests::retained_evidence();
    journal.plan_sha256.clone_from(&plan.plan_sha256);
    journal.operation_id.clone_from(&plan.operation_id);
    for completion in [
        FleetEnsureCompletion::InProgress,
        FleetEnsureCompletion::Prepared,
        FleetEnsureCompletion::ReplanRequired,
        FleetEnsureCompletion::Converged,
    ] {
        journal.completion = completion;
        write_plan(&paths, &plan).unwrap();
        write_journal(&paths, &journal).unwrap();
        let before = fs::read(&paths.journal).unwrap();
        let operation = retained(&paths, &request).unwrap();
        let report = report(&request, "network".into(), 1000, operation);
        assert_eq!(
            report
                .blockers
                .contains(&ReadinessBlocker::RetainedOperation),
            completion != FleetEnsureCompletion::Converged
        );
        assert_eq!(fs::read(&paths.journal).unwrap(), before);
        assert!(!paths.lock.exists());
    }
    fs::write(&paths.journal, b"incomplete").unwrap();
    assert!(matches!(
        retained(&paths, &request),
        Err(FleetReadinessError::State(_))
    ));
    fs::remove_dir_all(root).unwrap();
}

#[test]
fn unsafe_paths_and_unreadable_retained_evidence_fail_before_signer_or_network_access() {
    let root = temp_dir("readiness-invalid");
    let mut request = request(&root);
    request.fleet = "../outside";
    assert!(matches!(
        inspect(&request),
        Err(FleetReadinessError::Policy(_))
    ));
    assert!(!root.exists());
    request.fleet = "fleet";
    let paths = EnsurePaths::under(&root, "local", "fleet");
    fs::create_dir_all(paths.journal.parent().unwrap()).unwrap();
    fs::write(&paths.journal, b"incomplete").unwrap();
    assert!(matches!(
        inspect(&request),
        Err(FleetReadinessError::State(_))
    ));
    assert_eq!(fs::read(&paths.journal).unwrap(), b"incomplete");
    fs::remove_dir_all(root).unwrap();
}

#[test]
fn readiness_requires_exact_signer_and_network_without_anonymous_authority() {
    let mainnet = CanonicalNetworkId::ic_mainnet();
    let local = "00".repeat(32).parse::<CanonicalNetworkId>().unwrap();
    let signer = Principal::self_authenticating(b"operator");
    verify_authority(signer, signer, &mainnet, &mainnet).unwrap();
    for (expected, actual, network) in [
        (signer, Principal::anonymous(), &mainnet),
        (Principal::anonymous(), Principal::anonymous(), &mainnet),
        (signer, signer, &local),
    ] {
        assert!(matches!(
            verify_authority(expected, actual, &mainnet, network),
            Err(FleetReadinessError::AuthorityMismatch)
        ));
    }
}