apimock-config 5.15.0

Configuration model for apimock: loading, validation, editing, saving.
Documentation
//! RFC 016 — per-condition NodeId addressability.

use super::common::make_workspace_with_headers_and_body;
use crate::{
    view::{ConfigFileKind, EditCommand, NodeKind},
    workspace::Workspace,
};

#[test]
fn add_header_condition_creates_condition() {
    let (dir, root) = make_workspace_with_headers_and_body();
    let mut ws = Workspace::load(root).expect("load");
    let snap = ws.snapshot();
    let rule_id = snap
        .files
        .iter()
        .find(|f| matches!(f.kind, ConfigFileKind::RuleSet))
        .unwrap()
        .nodes
        .iter()
        .find(|n| matches!(n.kind, NodeKind::Rule))
        .unwrap()
        .id;

    let result = ws
        .apply(EditCommand::AddHeaderCondition {
            rule_id,
            condition: crate::view::HeaderConditionPayload {
                name: "x-new-header".to_owned(),
                op: crate::view::HeaderOp::Equal,
                value: Some("new-value".to_owned()),
            },
        })
        .expect("add ok");

    assert!(
        !result.changed_nodes.is_empty(),
        "should return changed node ids"
    );

    // Verify the condition was actually added.
    let rule = &ws.config().service.rule_sets[0].rules[0];
    assert!(rule.when.request.headers.is_some());
    let headers = rule.when.request.headers.as_ref().unwrap();
    assert!(
        headers.0.contains_key("x-new-header"),
        "header should be present"
    );
    let _ = dir;
}

#[test]
fn remove_header_condition_deletes_it() {
    let (_dir, root) = make_workspace_with_headers_and_body();
    let mut ws = Workspace::load(root).expect("load");
    let snap = ws.snapshot();
    let rule_id = snap
        .files
        .iter()
        .find(|f| matches!(f.kind, ConfigFileKind::RuleSet))
        .unwrap()
        .nodes
        .iter()
        .find(|n| matches!(n.kind, NodeKind::Rule))
        .unwrap()
        .id;

    // Add a header condition first so we have one to remove.
    let add_result = ws
        .apply(EditCommand::AddHeaderCondition {
            rule_id,
            condition: crate::view::HeaderConditionPayload {
                name: "x-remove-me".to_owned(),
                op: crate::view::HeaderOp::Equal,
                value: Some("gone".to_owned()),
            },
        })
        .expect("add");

    let cond_id = add_result
        .changed_nodes
        .iter()
        .copied()
        .find(|id| *id != rule_id)
        .expect("cond id");

    // Now remove it.
    ws.apply(EditCommand::RemoveHeaderCondition { id: cond_id })
        .expect("remove");

    let rule = &ws.config().service.rule_sets[0].rules[0];
    let absent = rule
        .when
        .request
        .headers
        .as_ref()
        .map(|h| !h.0.contains_key("x-remove-me"))
        .unwrap_or(true);
    assert!(absent, "header should be removed");
}

#[test]
fn add_body_condition_creates_condition() {
    let (_dir, root) = make_workspace_with_headers_and_body();
    let mut ws = Workspace::load(root).expect("load");
    let snap = ws.snapshot();
    let rule_id = snap
        .files
        .iter()
        .find(|f| matches!(f.kind, ConfigFileKind::RuleSet))
        .unwrap()
        .nodes
        .iter()
        .find(|n| matches!(n.kind, NodeKind::Rule))
        .unwrap()
        .id;

    ws.apply(EditCommand::AddBodyCondition {
        rule_id,
        condition: crate::view::BodyConditionPayload {
            kind: crate::view::BodyConditionKind::Json,
            path: "user.role".to_owned(),
            op: crate::view::BodyOp::Equal,
            value: serde_json::Value::String("admin".to_owned()),
        },
    })
    .expect("add body condition");

    let rule = &ws.config().service.rule_sets[0].rules[0];
    assert!(
        rule.when.request.body.is_some(),
        "body conditions should exist"
    );
}

#[test]
fn remove_body_condition_deletes_it() {
    let (_dir, root) = make_workspace_with_headers_and_body();
    let mut ws = Workspace::load(root).expect("load");
    let snap = ws.snapshot();
    let rule_id = snap
        .files
        .iter()
        .find(|f| matches!(f.kind, ConfigFileKind::RuleSet))
        .unwrap()
        .nodes
        .iter()
        .find(|n| matches!(n.kind, NodeKind::Rule))
        .unwrap()
        .id;

    let add_result = ws
        .apply(EditCommand::AddBodyCondition {
            rule_id,
            condition: crate::view::BodyConditionPayload {
                kind: crate::view::BodyConditionKind::Json,
                path: "temp.field".to_owned(),
                op: crate::view::BodyOp::Equal,
                value: serde_json::Value::String("x".to_owned()),
            },
        })
        .expect("add");

    let cond_id = add_result
        .changed_nodes
        .iter()
        .copied()
        .find(|id| *id != rule_id)
        .expect("cond id");

    ws.apply(EditCommand::RemoveBodyCondition { id: cond_id })
        .expect("remove");
}