canic-host 0.111.0

Host-side App build and desired-state Fleet reconciliation library for Canic workspaces
Documentation
use super::*;
use crate::{canister_build::CanisterBuildProfile, test_support::temp_dir};
use canic_contracts::ids::BuildNetwork;
use canic_core::role_contract::CanicFeatureKey;

#[test]
fn coordinator_declaration_pass_exports_candid_only_from_the_selected_leaf() {
    let workspace_root = Path::new(env!("CARGO_MANIFEST_DIR")).join("../..");
    let mut context = WorkspaceBuildContext {
        role: FLEET_COORDINATOR_ROLE.to_string(),
        profile: CanisterBuildProfile::Fast,
        environment: "local".to_string(),
        build_network: BuildNetwork::Local,
        workspace_root: workspace_root.clone(),
        icp_root: workspace_root,
        config_path: PathBuf::from("canic.toml"),
        local_replica: None,
        refresh_canonical_infrastructure_did: false,
        release_build_id: None,
    };
    let manifest = Path::new("/workspace/coordinator/Cargo.toml");

    let local_command = coordinator_cargo_build_command(&context, manifest, true);
    let local = local_command
        .get_args()
        .map(|argument| argument.to_string_lossy().into_owned())
        .collect::<Vec<_>>();
    assert_eq!(local.first().map(String::as_str), Some("rustc"));
    assert!(local.contains(&"--locked".to_string()));
    assert!(
        local
            .windows(2)
            .any(|arguments| arguments == ["--cfg", "canic_export_candid"])
    );
    assert!(local.contains(&"--check-cfg=cfg(canic_export_candid)".to_string()));
    assert_eq!(
        local_command.get_envs().find(|(key, _)| {
            *key == std::ffi::OsStr::new(canic_core::role_contract::CANONICAL_CANDID_BUILD_ENV)
        }),
        Some((
            std::ffi::OsStr::new(canic_core::role_contract::CANONICAL_CANDID_BUILD_ENV),
            Some(std::ffi::OsStr::new("1")),
        ))
    );

    context.build_network = BuildNetwork::Ic;
    let ic = coordinator_cargo_build_command(&context, manifest, false)
        .get_args()
        .map(|argument| argument.to_string_lossy().into_owned())
        .collect::<Vec<_>>();
    assert_eq!(ic.first().map(String::as_str), Some("build"));
    assert!(ic.contains(&"--locked".to_string()));
    assert_eq!(
        coordinator_cargo_build_command(&context, manifest, false)
            .get_envs()
            .find(|(key, _)| {
                *key == std::ffi::OsStr::new(canic_core::role_contract::CANONICAL_CANDID_BUILD_ENV)
            }),
        Some((
            std::ffi::OsStr::new(canic_core::role_contract::CANONICAL_CANDID_BUILD_ENV),
            None,
        ))
    );
}

#[test]
fn generated_fleet_coordinator_wrapper_satisfies_its_runtime_only_contract() {
    let root = temp_dir("canic-generated-fleet-coordinator-contract");
    let workspace_root = Path::new(env!("CARGO_MANIFEST_DIR")).join("../..");
    let context = WorkspaceBuildContext {
        role: FLEET_COORDINATOR_ROLE.to_string(),
        profile: CanisterBuildProfile::Fast,
        environment: "test".to_string(),
        build_network: BuildNetwork::Ic,
        workspace_root,
        icp_root: root.clone(),
        config_path: root.join("canic.toml"),
        local_replica: None,
        refresh_canonical_infrastructure_did: false,
        release_build_id: None,
    };

    let source =
        resolve_bootstrap_fleet_coordinator_source(&context).expect("generate Coordinator package");
    assert!(
        source
            .canonical_did_path
            .ends_with("canic/candid/fleet_coordinator.did")
    );
    assert_eq!(source.package_version, env!("CARGO_PKG_VERSION"));
    let manifest_path = source.manifest_path;
    let manifest = fs::read_to_string(&manifest_path).expect("read generated manifest");
    let runtime = fs::read_to_string(
        manifest_path
            .parent()
            .expect("wrapper manifest parent")
            .join("src/lib.rs"),
    )
    .expect("read generated runtime");
    assert!(manifest.contains("app = \"fleet_coordinator\""));
    assert!(manifest.contains("role = \"fleet_coordinator\""));
    assert!(manifest.contains("default-features = false"));
    assert!(manifest.contains("features = [\"fleet-coordinator-canister\"]"));
    assert!(!manifest.contains("[build-dependencies]"));
    assert_eq!(
        runtime,
        "canic::start_fleet_coordinator!();\ncanic::finish!();\n"
    );

    let validation =
        validate_built_in_fleet_coordinator_package(&manifest_path, PackageValidationMode::Build);
    let RolePackageValidation::Supported(evidence) = validation else {
        panic!("generated wrapper should satisfy the package contract: {validation:?}");
    };
    assert_eq!(
        evidence.direct_features,
        std::collections::BTreeSet::from([CanicFeatureKey::FleetCoordinatorCanister])
    );

    fs::remove_dir_all(root).expect("clean temp dir");
}