canic-host 0.69.4

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

#[test]
fn promotion_plan_transform_validation_accepts_generated_transform() {
    let request = PromotionPlanTransformRequest {
        promoted_plan_id: "promoted-plan-1".to_string(),
        target_plan: sample_promotion_target_plan(),
        inputs: vec![sample_role_promotion_input(
            PromotionArtifactLevelV1::SealedWasm,
        )],
    };
    let transform = promoted_deployment_plan_transform_from_inputs(&request)
        .expect("transform should be produced");

    validate_promotion_plan_transform(&transform).expect("generated transform should validate");
}

#[test]
fn promotion_plan_transform_validation_rejects_schema_drift() {
    let request = PromotionPlanTransformRequest {
        promoted_plan_id: "promoted-plan-1".to_string(),
        target_plan: sample_promotion_target_plan(),
        inputs: vec![sample_role_promotion_input(
            PromotionArtifactLevelV1::SealedWasm,
        )],
    };
    let mut transform = promoted_deployment_plan_transform_from_inputs(&request)
        .expect("transform should be produced");
    transform.schema_version += 1;

    let err = validate_promotion_plan_transform(&transform).expect_err("schema drift should fail");
    std::assert_matches!(
        err,
        PromotionPlanTransformError::SchemaVersionMismatch { .. }
    );
}

#[test]
fn promotion_plan_transform_validation_rejects_plan_id_mismatch() {
    let request = PromotionPlanTransformRequest {
        promoted_plan_id: "promoted-plan-1".to_string(),
        target_plan: sample_promotion_target_plan(),
        inputs: vec![sample_role_promotion_input(
            PromotionArtifactLevelV1::SealedWasm,
        )],
    };
    let mut transform = promoted_deployment_plan_transform_from_inputs(&request)
        .expect("transform should be produced");
    transform.promoted_plan.plan_id = "different-plan".to_string();

    let err =
        validate_promotion_plan_transform(&transform).expect_err("plan id mismatch should fail");
    std::assert_matches!(
        err,
        PromotionPlanTransformError::PromotedPlanIdMismatch { .. }
    );
}

#[test]
fn promotion_plan_transform_validation_rejects_duplicate_roles() {
    let request = PromotionPlanTransformRequest {
        promoted_plan_id: "promoted-plan-1".to_string(),
        target_plan: sample_promotion_target_plan(),
        inputs: vec![sample_role_promotion_input(
            PromotionArtifactLevelV1::SealedWasm,
        )],
    };
    let mut transform = promoted_deployment_plan_transform_from_inputs(&request)
        .expect("transform should be produced");
    transform.roles.push(transform.roles[0].clone());

    let err =
        validate_promotion_plan_transform(&transform).expect_err("duplicate role should fail");
    std::assert_matches!(
        err,
        PromotionPlanTransformError::DuplicateRole { role } if role == "root"
    );
}

#[test]
fn promotion_plan_transform_validation_rejects_missing_promoted_role() {
    let request = PromotionPlanTransformRequest {
        promoted_plan_id: "promoted-plan-1".to_string(),
        target_plan: sample_promotion_target_plan(),
        inputs: vec![sample_role_promotion_input(
            PromotionArtifactLevelV1::SealedWasm,
        )],
    };
    let mut transform = promoted_deployment_plan_transform_from_inputs(&request)
        .expect("transform should be produced");
    transform.promoted_plan.role_artifacts.clear();

    let err = validate_promotion_plan_transform(&transform)
        .expect_err("missing promoted role should fail");
    std::assert_matches!(
        err,
        PromotionPlanTransformError::PromotedRoleMissing { role } if role == "root"
    );
}

#[test]
fn promotion_plan_transform_validation_rejects_stale_lineage_digest() {
    let request = PromotionPlanTransformRequest {
        promoted_plan_id: "promoted-plan-1".to_string(),
        target_plan: sample_promotion_target_plan(),
        inputs: vec![sample_role_promotion_input(
            PromotionArtifactLevelV1::SealedWasm,
        )],
    };
    let mut transform = promoted_deployment_plan_transform_from_inputs(&request)
        .expect("transform should be produced");
    transform.promotion_plan_lineage_digest = sample_sha256("9");

    let err = validate_promotion_plan_transform(&transform)
        .expect_err("stale lineage digest should fail");
    std::assert_matches!(
        err,
        PromotionPlanTransformError::RoleStateMismatch {
            role,
            field: "promotion_plan_lineage_digest"
        } if role == "promotion_plan_lineage"
    );
}

#[test]
fn promotion_plan_lineage_digest_changes_when_materialization_link_changes() {
    let mut target_plan = sample_promotion_target_plan();
    target_plan.role_artifacts[0].wasm_sha256 = Some(sample_sha256("5"));
    target_plan.role_artifacts[0].wasm_gz_sha256 = Some(sample_sha256("6"));
    target_plan.role_artifacts[0].installed_module_hash = Some(sample_sha256("7"));
    target_plan.role_artifacts[0].candid_sha256 = Some(sample_sha256("8"));
    let request = PromotionPlanTransformWithMaterializationRequest {
        promoted_plan_id: "promoted-plan-1".to_string(),
        target_plan,
        inputs: vec![sample_role_promotion_input(
            PromotionArtifactLevelV1::SourceBuild,
        )],
        materialization_evidence: vec![sample_build_materialization_evidence()],
    };
    let transform = promoted_deployment_plan_transform_from_inputs_with_materialization(&request)
        .expect("source-build transform should link evidence");
    let mut changed_roles = transform.roles.clone();
    changed_roles[0]
        .source_build_materialization
        .as_mut()
        .expect("materialization link should exist")
        .evidence_id = "different-evidence".to_string();

    let changed_digest = promotion_plan_lineage_digest(
        &transform.target_plan_id,
        &transform.promoted_plan_id,
        &transform.promoted_plan,
        &changed_roles,
    );

    assert_ne!(changed_digest, transform.promotion_plan_lineage_digest);
}

#[test]
fn promotion_plan_transform_validation_rejects_stale_after_summary() {
    let request = PromotionPlanTransformRequest {
        promoted_plan_id: "promoted-plan-1".to_string(),
        target_plan: sample_promotion_target_plan(),
        inputs: vec![sample_role_promotion_input(
            PromotionArtifactLevelV1::SealedWasm,
        )],
    };
    let mut transform = promoted_deployment_plan_transform_from_inputs(&request)
        .expect("transform should be produced");
    transform.roles[0].wasm_gz_sha256_after = Some(sample_sha256("f"));

    let err = validate_promotion_plan_transform(&transform).expect_err("stale summary should fail");
    std::assert_matches!(
        err,
        PromotionPlanTransformError::RoleStateMismatch {
            role,
            field: "wasm_gz_sha256_after"
        } if role == "root"
    );
}

#[test]
fn promotion_plan_transform_validation_rejects_stale_change_flag() {
    let mut target_plan = sample_promotion_target_plan();
    target_plan.role_artifacts[0].wasm_gz_sha256 = Some(sample_sha256("f"));
    let mut input = sample_role_promotion_input(PromotionArtifactLevelV1::SealedWasm);
    input.require_byte_identical_wasm = false;
    let request = PromotionPlanTransformRequest {
        promoted_plan_id: "promoted-plan-1".to_string(),
        target_plan,
        inputs: vec![input],
    };
    let mut transform = promoted_deployment_plan_transform_from_inputs(&request)
        .expect("transform should be produced");
    transform.roles[0].artifact_identity_changed = false;

    let err = validate_promotion_plan_transform(&transform).expect_err("stale flag should fail");
    std::assert_matches!(
        err,
        PromotionPlanTransformError::RoleStateMismatch {
            role,
            field: "artifact_identity_changed"
        } if role == "root"
    );
}