haematite-cli 0.33.0

The haematite command: serve a store, its door and Studio, answer MCP, query with jq, and host the store's assistant seat
Documentation
use std::error::Error;

use super::{ActorKind, Row, key, version_prefix};
use crate::serve::contracts::{MutationRequest, ResolvedMutation};
use crate::serve::protocol::Version;
use serde_json::{Value, json};

type TestResult = Result<(), Box<dyn Error>>;

const fn version(sequence: u64) -> Version {
    Version {
        generation: 7,
        sequence,
    }
}

fn request(id: &str, caller: &Value, change: &Value) -> Result<ResolvedMutation, Box<dyn Error>> {
    Ok(MutationRequest::decode(&serde_json::to_vec(&json!({
        "request_id":id, "branch":"main", "caller":caller,
        "contract":{"kind":"dependencies", "origin":version(1), "reads":[]},
        "change":change,
    }))?)?
    .resolve("operator-not-the-author")?)
}

fn person(subject: &str) -> Value {
    json!({"issuer":"lys", "subject":subject})
}

fn put() -> Value {
    json!({"kind":"document.put", "value":{"collection":"charts", "document_id":"child-1", "document":{"private":"body-marker"}}})
}

fn row() -> Result<Row, Box<dyn Error>> {
    Ok(Row::for_request(
        &request("write", &person("doctor-a"), &put())?,
        version(2),
    )?)
}

fn decode_value(value: &Value) -> Result<Row, crate::serve::storage::Failure> {
    Row::decode(
        &key(version(2), "write")?,
        &serde_json::to_vec(value).map_err(crate::serve::storage::Failure::storage)?,
    )
}

#[test]
fn two_callers_in_one_version_keep_two_rows_and_their_own_callers() -> TestResult {
    let first = Row::for_request(&request("first", &person("doctor-a"), &put())?, version(2))?;
    let second = Row::for_request(&request("second", &person("doctor-b"), &put())?, version(2))?;
    assert_ne!(first.key()?, second.key()?);
    let first = Row::decode(&first.key()?, &first.encode()?)?;
    let second = Row::decode(&second.key()?, &second.encode()?)?;
    assert_eq!(first.caller().subject(), "doctor-a");
    assert_eq!(second.caller().subject(), "doctor-b");
    assert_eq!(first.version(), second.version());
    Ok(())
}

#[test]
fn three_imported_documents_have_one_row_naming_none_of_them() -> TestResult {
    let import = json!({"kind":"documents.put_many", "value":{"collection":"charts", "documents":[
        {"document_id":"a", "document":{"private":"body-a"}},
        {"document_id":"b", "document":{"private":"body-b"}},
        {"document_id":"c", "document":{"private":"body-c"}}
    ]}});
    let row = Row::for_request(
        &request("import", &person("doctor-a"), &import)?,
        version(2),
    )?;
    let bytes = row.encode()?;
    let value: Value = serde_json::from_slice(&bytes)?;
    assert!(value.get("change").is_none(), "{value}");
    assert_eq!(value["request_id"], "import");
    assert!(!String::from_utf8(bytes)?.contains("body-"));
    Ok(())
}

#[test]
fn moving_a_row_to_another_request_key_is_refused() -> TestResult {
    let row = row()?;
    let error = Row::decode(&key(version(2), "other")?, &row.encode()?)
        .err()
        .ok_or("moved row accepted")?;
    assert_eq!(error.code, "change_record_key_mismatch");
    Ok(())
}

#[test]
fn moving_a_row_to_another_version_key_is_refused() -> TestResult {
    let row = row()?;
    let error = Row::decode(&key(version(3), "write")?, &row.encode()?)
        .err()
        .ok_or("moved row accepted")?;
    assert_eq!(error.code, "change_record_key_mismatch");
    Ok(())
}

#[test]
fn person_and_agent_keep_the_subject_and_responsible_person() -> TestResult {
    let person = row()?;
    assert_eq!(person.actor_kind(), ActorKind::Person);
    assert_eq!(person.caller().responsible(), None);
    let caller = json!({"issuer":"lys", "subject":"agent-a", "responsible":"doctor-a"});
    let agent = Row::for_request(&request("agent", &caller, &put())?, version(2))?;
    let decoded = Row::decode(&agent.key()?, &agent.encode()?)?;
    assert_eq!(decoded.actor_kind(), ActorKind::Agent);
    assert_eq!(decoded.caller().issuer(), "lys");
    assert_eq!(decoded.caller().subject(), "agent-a");
    assert_eq!(decoded.caller().responsible(), Some("doctor-a"));
    Ok(())
}

#[test]
fn one_request_id_at_two_versions_has_two_distinct_keys() -> TestResult {
    let request = request("write", &person("doctor-a"), &put())?;
    let first = Row::for_request(&request, version(2))?;
    let second = Row::for_request(&request, version(3))?;
    assert_ne!(first.key()?, second.key()?);
    assert!(first.key()? < second.key()?);
    assert_eq!(first.request_id(), second.request_id());
    assert_eq!(first.origin(), version(1));
    assert_eq!(second.origin(), version(1));
    Ok(())
}

#[test]
fn keys_sort_numerically_across_generation_and_sequence_boundaries() -> TestResult {
    let versions = [
        Version {
            generation: 1,
            sequence: 255,
        },
        Version {
            generation: 1,
            sequence: 256,
        },
        Version {
            generation: 1,
            sequence: u64::MAX,
        },
        Version {
            generation: 2,
            sequence: 0,
        },
    ];
    let keys = versions
        .into_iter()
        .map(|at| key(at, "write"))
        .collect::<Result<Vec<_>, _>>()?;
    assert!(keys.windows(2).all(|pair| pair[0] < pair[1]));
    assert_eq!(version_prefix(version(2)).len(), 19);
    assert!(key(version(2), "write")?.starts_with(&version_prefix(version(2))));
    Ok(())
}

#[test]
fn a_document_row_names_its_author_and_keeps_no_target_or_body() -> TestResult {
    let row = row()?;
    let bytes = row.encode()?;
    assert!(bytes.starts_with(b"{\"format\":2,"));
    let text = String::from_utf8(bytes)?;
    assert!(!text.contains("body-marker"), "{text}");
    assert!(!text.contains("child-1"), "{text}");
    assert_eq!(row.caller().subject(), "doctor-a");
    Ok(())
}

#[test]
fn unknown_format_and_unknown_fields_are_refused() -> TestResult {
    let mut value = serde_json::to_value(row()?)?;
    value["format"] = json!(3);
    assert_eq!(
        decode_value(&value)
            .err()
            .ok_or("unknown format accepted")?
            .code,
        "change_record_format_unsupported"
    );
    value["format"] = json!(2);
    value["credential"] = json!("must-not-be-kept");
    assert_eq!(
        decode_value(&value)
            .err()
            .ok_or("unknown field accepted")?
            .code,
        "change_record_corrupt"
    );
    Ok(())
}

#[test]
fn an_anonymous_stored_row_is_refused_without_an_operator_fallback() -> TestResult {
    let mut value = serde_json::to_value(row()?)?;
    value
        .as_object_mut()
        .ok_or("not an object")?
        .remove("caller");
    assert_eq!(
        decode_value(&value)
            .err()
            .ok_or("anonymous row accepted")?
            .code,
        "change_record_corrupt"
    );
    Ok(())
}

#[test]
fn malformed_keys_and_invalid_request_ids_are_refused() -> TestResult {
    let row = row()?;
    for malformed in [b"a\0".as_slice(), b"z\0missing", b"a\0short"] {
        assert_eq!(
            Row::decode(malformed, &row.encode()?)
                .err()
                .ok_or("invalid key accepted")?
                .code,
            "change_record_key_invalid"
        );
    }
    assert!(key(version(2), "").is_err());
    assert!(key(version(2), "a\0b").is_err());
    Ok(())
}

#[test]
fn every_change_kind_writes_a_row_without_its_change() -> TestResult {
    let from = json!({"collection":"charts", "document_id":"a"});
    let to = json!({"collection":"charts", "document_id":"b"});
    let changes = [
        json!({"kind":"collection.put", "value":{"collection":"charts", "schema":{"private":"body-marker"}}}),
        json!({"kind":"document.delete", "value":{"collection":"charts", "document_id":"a"}}),
        json!({"kind":"edge.put", "value":{"relation":"link", "from":from, "to":to, "properties":{"private":"body-marker"}}}),
        json!({"kind":"edge.delete", "value":{"relation":"link", "from":from, "to":to}}),
        json!({"kind":"vector.put", "value":{"collection":"charts", "document_id":"a", "field":"embedding", "vector":[1.0,2.0]}}),
        json!({"kind":"vector.delete", "value":{"collection":"charts", "document_id":"a", "field":"embedding"}}),
        json!({"kind":"relation.put", "value":{"relation":"link", "from_collection":"charts", "to_collection":"charts", "cardinality":"many_to_many"}}),
        json!({"kind":"relation.delete", "value":{"relation":"link"}}),
        json!({"kind":"branch.fork", "value":{"name":"work", "from":version(1)}}),
        json!({"kind":"branch.discard", "value":{"name":"work"}}),
    ];
    for (index, change) in changes.into_iter().enumerate() {
        let row = Row::for_request(
            &request(&format!("request-{index}"), &person("doctor-a"), &change)?,
            version(2),
        )?;
        let encoded = row.encode()?;
        let decoded = Row::decode(&row.key()?, &encoded)?;
        let value = serde_json::to_value(decoded)?;
        assert!(value.get("change").is_none(), "{value}");
        assert_eq!(value["request_id"], format!("request-{index}"));
        assert!(!String::from_utf8(encoded)?.contains("body-marker"));
    }
    Ok(())
}

#[test]
fn nested_credentials_and_a_format_two_change_are_refused() -> TestResult {
    let mut value = serde_json::to_value(row()?)?;
    value["caller"]["token"] = json!("must-not-be-kept");
    assert_eq!(
        decode_value(&value)
            .err()
            .ok_or("credential accepted")?
            .code,
        "change_record_corrupt"
    );
    value["caller"] = person("doctor-a");
    value["change"] =
        json!({"kind":"document.put", "collection":"charts", "document_id":"child-1"});
    assert_eq!(
        decode_value(&value)
            .err()
            .ok_or("a format 2 row with a change accepted")?
            .code,
        "change_record_corrupt"
    );
    Ok(())
}

#[test]
fn oversized_rows_are_refused() -> TestResult {
    let oversized = vec![b' '; super::MAX_ROW_BYTES + 1];
    assert_eq!(
        Row::decode(&key(version(2), "write")?, &oversized)
            .err()
            .ok_or("oversize accepted")?
            .code,
        "change_record_too_large"
    );
    Ok(())
}

#[test]
fn maximum_versions_and_utf8_request_ids_round_trip() -> TestResult {
    let at = Version {
        generation: u64::MAX,
        sequence: u64::MAX,
    };
    let request = request("é-clinician", &person("doctor-a"), &put())?;
    let row = Row::for_request(&request, at)?;
    let decoded = Row::decode(&row.key()?, &row.encode()?)?;
    assert_eq!(decoded.version(), at);
    assert_eq!(decoded.request_id(), "é-clinician");
    Ok(())
}

#[test]
fn an_invalid_request_id_is_refused_before_a_row_is_made() -> TestResult {
    let caller = crate::serve::contracts::Caller::local("tom")?;
    for request_id in ["", "a\0b"] {
        assert_eq!(
            Row::by(request_id, &caller, version(1), version(2))
                .err()
                .ok_or("invalid request id recorded")?
                .code,
            "invalid_identifier"
        );
    }
    Ok(())
}

#[test]
fn a_vector_import_row_holds_no_vectors() -> TestResult {
    let import = json!({"kind":"vectors.put_many", "value":{"vectors":[
        {"collection":"charts", "document_id":"a", "field":"supplied", "vector":[1.0]},
        {"collection":"charts", "document_id":"b", "field":"supplied", "vector":[2.0]}
    ]}});
    let row = Row::for_request(
        &request("vectors", &person("doctor-a"), &import)?,
        version(2),
    )?;
    let decoded = Row::decode(&row.key()?, &row.encode()?)?;
    assert_eq!(decoded.request_id(), "vectors");
    let value: Value = serde_json::from_slice(&row.encode()?)?;
    assert!(value.get("change").is_none(), "{value}");
    Ok(())
}

#[test]
fn a_delete_of_three_hundred_ids_writes_the_row_a_delete_of_one_writes() -> TestResult {
    let delete = |count: usize| {
        let ids: Vec<_> = (0..count)
            .map(|index| format!("record-{index:03}"))
            .collect();
        json!({"kind":"documents.delete_many", "value":{"collection":"charts", "document_ids":ids}})
    };
    let one = Row::for_request(
        &request("delete", &person("doctor-a"), &delete(1))?,
        version(2),
    )?;
    let many = Row::for_request(
        &request("delete", &person("doctor-a"), &delete(300))?,
        version(2),
    )?;
    assert_eq!(one.encode()?, many.encode()?);
    let decoded = Row::decode(&many.key()?, &many.encode()?)?;
    assert_eq!(decoded.request_id(), "delete");
    assert_eq!(decoded.caller().subject(), "doctor-a");
    Ok(())
}

#[test]
fn a_format_one_row_is_read_without_its_change() -> TestResult {
    let mut value = serde_json::to_value(row()?)?;
    value["format"] = json!(1);
    value["change"] = json!({"kind":"documents.delete_many", "changes":[
        {"kind":"document.delete", "collection":"charts", "document_id":"a"}
    ]});
    let decoded = decode_value(&value)?;
    assert_eq!(
        decoded.author(),
        json!({"request_id":"write", "caller":{"issuer":"lys", "subject":"doctor-a"}})
    );
    let rewritten: Value = serde_json::from_slice(&decoded.encode()?)?;
    assert_eq!(rewritten["format"], 2);
    assert!(rewritten.get("change").is_none());
    let mut bare = serde_json::to_value(row()?)?;
    bare["format"] = json!(1);
    assert_eq!(
        decode_value(&bare)
            .err()
            .ok_or("a format 1 row without its change accepted")?
            .code,
        "change_record_corrupt"
    );
    Ok(())
}