canic-host 0.68.3

Host-side build, install, deployment, and fleet-template library for Canic workspaces
Documentation
use super::*;

#[test]
fn promotion_readiness_reports_ready_role_and_restage_warning() {
    let plan = sample_promotion_target_plan();
    let mut input = sample_role_promotion_input(PromotionArtifactLevelV1::SealedWasm);
    input.target_store_has_artifact = Some(false);

    let readiness = promotion_readiness_from_inputs("promotion-ready-1", &plan, &[input]);

    assert_eq!(readiness.schema_version, DEPLOYMENT_TRUTH_SCHEMA_VERSION);
    assert_eq!(readiness.target_plan_id, plan.plan_id);
    assert_eq!(readiness.status, PromotionReadinessStatusV1::Ready);
    assert!(readiness.blockers.is_empty());
    assert_eq!(readiness.warnings.len(), 1);
    assert_eq!(
        readiness.warnings[0].code,
        "promotion_target_store_restage_required"
    );
    assert_eq!(readiness.roles.len(), 1);
    assert_eq!(readiness.roles[0].byte_identical_wasm, Some(true));
    assert_eq!(readiness.roles[0].embedded_config_identical, Some(true));
    assert!(readiness.roles[0].restage_required);
    validate_promotion_readiness(&readiness).expect("readiness artifact should validate");
}

#[test]
fn promotion_readiness_blocks_sealed_wasm_embedded_config_mismatch() {
    let plan = sample_promotion_target_plan();
    let mut input = sample_role_promotion_input(PromotionArtifactLevelV1::SealedWasm);
    input.source.expected_canonical_embedded_config_sha256 = Some(sample_sha256("e"));

    let readiness = promotion_readiness_from_inputs("promotion-ready-1", &plan, &[input]);

    assert_eq!(readiness.status, PromotionReadinessStatusV1::Blocked);
    assert!(readiness.blockers.iter().any(|finding| {
        finding.code == "promotion_sealed_wasm_embedded_config_mismatch"
            && finding.subject.as_deref() == Some("root")
    }));
}

#[test]
fn source_build_promotion_allows_target_config_digest_change() {
    let plan = sample_promotion_target_plan();
    let mut input = sample_role_promotion_input(PromotionArtifactLevelV1::SourceBuild);
    input.source.expected_canonical_embedded_config_sha256 = Some(sample_sha256("e"));

    let readiness = promotion_readiness_from_inputs("promotion-ready-1", &plan, &[input]);

    assert_eq!(readiness.status, PromotionReadinessStatusV1::Ready);
    assert!(readiness.blockers.is_empty());
    assert_eq!(readiness.roles[0].embedded_config_identical, Some(false));
    validate_promotion_readiness(&readiness).expect("source-build readiness should validate");
}

#[test]
fn check_promotion_readiness_validates_and_returns_artifact() {
    let request = PromotionReadinessRequest {
        readiness_id: "promotion-ready-1".to_string(),
        target_plan: sample_promotion_target_plan(),
        inputs: vec![sample_role_promotion_input(
            PromotionArtifactLevelV1::SealedWasm,
        )],
    };

    let readiness = check_promotion_readiness(&request).expect("readiness should be valid");

    assert_eq!(readiness.readiness_id, "promotion-ready-1");
    assert_eq!(readiness.status, PromotionReadinessStatusV1::Ready);
    assert_eq!(readiness.roles.len(), 1);
}

#[test]
fn promotion_readiness_with_policy_blocks_source_build_when_sealed_bytes_are_required() {
    let input = sample_role_promotion_input(PromotionArtifactLevelV1::SourceBuild);
    let policy = sample_role_promotion_policy();

    let readiness = promotion_readiness_from_inputs_with_policy(
        "promotion-ready-1",
        &sample_promotion_target_plan(),
        &[input],
        &[policy],
    );

    assert_eq!(readiness.status, PromotionReadinessStatusV1::Blocked);
    assert!(readiness.blockers.iter().any(|finding| {
        finding.code == "promotion_policy_level_not_allowed"
            || finding.code == "promotion_policy_must_use_sealed_bytes"
    }));
    validate_promotion_readiness(&readiness).expect("policy-blocked readiness should validate");
}

#[test]
fn promotion_readiness_with_policy_accepts_byte_identical_source_build_policy() {
    let mut input = sample_role_promotion_input(PromotionArtifactLevelV1::SourceBuild);
    input.require_byte_identical_wasm = true;
    let mut policy = sample_role_promotion_policy();
    policy.allowed_promotion_levels = vec![PromotionArtifactLevelV1::SourceBuild];
    policy.requirements = vec![PromotionPolicyRequirementV1::ByteIdenticalWasm];

    let readiness = check_promotion_readiness_with_policy(&PromotionReadinessWithPolicyRequest {
        readiness_id: "promotion-ready-1".to_string(),
        target_plan: sample_promotion_target_plan(),
        inputs: vec![input],
        policies: vec![policy],
    })
    .expect("source-build policy readiness should validate");

    assert_eq!(readiness.status, PromotionReadinessStatusV1::Ready);
    assert!(readiness.blockers.is_empty());
}

#[test]
fn promotion_readiness_with_policy_reports_missing_role_policy() {
    let input = sample_role_promotion_input(PromotionArtifactLevelV1::SealedWasm);

    let readiness = promotion_readiness_from_inputs_with_policy(
        "promotion-ready-1",
        &sample_promotion_target_plan(),
        &[input],
        &[],
    );

    assert_eq!(readiness.status, PromotionReadinessStatusV1::Blocked);
    assert!(readiness.blockers.iter().any(|finding| {
        finding.code == "promotion_policy_missing" && finding.subject.as_deref() == Some("root")
    }));
    validate_promotion_readiness(&readiness).expect("missing-policy readiness should validate");
}

#[test]
fn check_promotion_readiness_rejects_blank_readiness_id() {
    let request = PromotionReadinessRequest {
        readiness_id: " ".to_string(),
        target_plan: sample_promotion_target_plan(),
        inputs: vec![sample_role_promotion_input(
            PromotionArtifactLevelV1::SealedWasm,
        )],
    };

    let err = check_promotion_readiness(&request).expect_err("blank readiness id should fail");
    std::assert_matches!(
        err,
        PromotionReadinessError::MissingRequiredField {
            field: "readiness_id"
        }
    );
}

#[test]
fn promoted_deployment_plan_rejects_blocked_readiness() {
    let mut input = sample_role_promotion_input(PromotionArtifactLevelV1::SealedWasm);
    input.source.expected_canonical_embedded_config_sha256 = Some(sample_sha256("e"));
    let request = PromotionPlanTransformRequest {
        promoted_plan_id: "promoted-plan-1".to_string(),
        target_plan: sample_promotion_target_plan(),
        inputs: vec![input],
    };

    let err =
        promoted_deployment_plan_from_inputs(&request).expect_err("blocked readiness should fail");
    std::assert_matches!(
        err,
        PromotionPlanTransformError::ReadinessBlocked { blocker_count: 1 }
    );
}

#[test]
fn promoted_deployment_plan_rejects_blank_plan_id() {
    let request = PromotionPlanTransformRequest {
        promoted_plan_id: " ".to_string(),
        target_plan: sample_promotion_target_plan(),
        inputs: vec![sample_role_promotion_input(
            PromotionArtifactLevelV1::SealedWasm,
        )],
    };

    let err =
        promoted_deployment_plan_from_inputs(&request).expect_err("blank plan id should fail");
    std::assert_matches!(
        err,
        PromotionPlanTransformError::MissingRequiredField {
            field: "promoted_plan_id"
        }
    );
}

#[test]
fn promotion_readiness_blocks_source_role_mismatch() {
    let plan = sample_promotion_target_plan();
    let mut input = sample_role_promotion_input(PromotionArtifactLevelV1::SourceBuild);
    input.source.role = "other".to_string();

    let readiness = promotion_readiness_from_inputs("promotion-ready-1", &plan, &[input]);

    assert_eq!(readiness.status, PromotionReadinessStatusV1::Blocked);
    assert!(readiness.blockers.iter().any(|finding| {
        finding.code == "promotion_source_role_mismatch"
            && finding.subject.as_deref() == Some("root")
    }));
}

#[test]
fn promotion_readiness_blocks_missing_target_role() {
    let plan = sample_plan();
    let mut input = sample_role_promotion_input(PromotionArtifactLevelV1::SourceBuild);
    input.role = "missing".to_string();
    input.source.role = "missing".to_string();

    let readiness = promotion_readiness_from_inputs("promotion-ready-1", &plan, &[input]);

    assert_eq!(readiness.status, PromotionReadinessStatusV1::Blocked);
    assert!(readiness.roles.is_empty());
    assert!(readiness.blockers.iter().any(|finding| {
        finding.code == "promotion_target_role_missing"
            && finding.subject.as_deref() == Some("missing")
    }));
}

#[test]
fn promotion_readiness_blocks_invalid_artifact_source() {
    let plan = sample_promotion_target_plan();
    let mut input = sample_role_promotion_input(PromotionArtifactLevelV1::SourceBuild);
    input.source.expected_wasm_sha256 = None;
    input.source.expected_wasm_gz_sha256 = None;

    let readiness = promotion_readiness_from_inputs("promotion-ready-1", &plan, &[input]);

    assert_eq!(readiness.status, PromotionReadinessStatusV1::Blocked);
    assert!(readiness.blockers.iter().any(|finding| {
        finding.code == "promotion_artifact_source_invalid"
            && finding.subject.as_deref() == Some("root")
    }));
    validate_promotion_readiness(&readiness).expect("blocked readiness artifact should validate");
}