Skip to main content

Module testkit

Module testkit 

Source
Expand description

A conformance kit for Resolver implementations (feature testkit).

A resolver is read-only, so the kit never writes through it. Instead it hands out Fixtures (key documents, descriptors, receipts, and the versions of stored cells), the caller loads them into the resolver under test however that resolver is filled (maps, a database, files), and the kit then verifies receipts through it and looks things up in it. Each check returns a Report of what failed; Kit::check runs all of them.

use datumesh_core::testkit::{Fixtures, Kit};
use datumesh_core::MapResolver;

fn load(fx: &Fixtures) -> MapResolver {
    let mut m = MapResolver::new();
    for (fn_hash, bytes) in &fx.descriptors {
        m.insert_descriptor(fn_hash.as_str(), bytes.as_slice());
    }
    for (hash, bytes) in &fx.receipts {
        m.insert_receipt(hash.as_str(), bytes.as_slice());
    }
    // MapResolver keeps one value per cell: the versions come in tx order, so the
    // latest one stays. A time-aware resolver loads them all.
    for v in &fx.versions {
        m.insert_value(v.cell_id.as_str(), v.value.clone());
    }
    m
}

if let Err(report) = Kit::new().run(load) {
    panic!("{report}");
}

The checks:

  • check_lazy_calls: through a Recording wrapper, verify asks the resolver only for what step 7 reaches: the descriptor once; the inputs in order up to the first that fails; evaluate once, after 7.1-7.5, with the receipt’s cell and asof; and nothing at all when the receipt fails before step 7.
  • check_unavailable: an unknown fn_hash is E_FN_UNAVAILABLE, an input receipt it does not have is E_INPUT_UNAVAILABLE (first or second input), a function it cannot evaluate is E_EVAL_UNAVAILABLE (ok, level signed), and looking up unknown or malformed hashes (empty, uppercase, too long, non-hex, NUL, SQL or path syntax, non-ASCII) gives None without panicking.
  • check_bytes: descriptor and receipt return exactly the bytes loaded (all fixture bytes are canonical JSON, so a resolver that canonicalises what it is given still passes).
  • check_asof: evaluate receives the receipt’s asof, and stored cells recompute. With Kit::time_aware, a cell with versions at several times gives the value of its latest version with tx <= asof (inclusive at each tx, None before the first), both through verify and through direct evaluate calls.

The kit expects a resolver to evaluate only what the fixtures give it: the versions of stored cells. Computed cells (convert, language expr) are not evaluable, so receipts of them end at E_EVAL_UNAVAILABLE. A panic in the resolver propagates to the caller.

The fixtures come from the specification’s vectors (revision spec-0.2.1), in canonical form, plus receipts signed for the kit with the vectors’ seeds (feature sign): a second fx_rate cell (EUR/CHF) with versions at two times, and a convert receipt whose first input is not loaded. They are embedded in the crate (src/testkit/data.rs), generated and checked against spec/ by the crate’s test tests/testkit_data.rs.

Structs§

Fixtures
What the resolver under test is loaded with. All bytes are canonical JSON (JCS).
Kit
The resolver test kit: the fixtures and the checks. See the module documentation.
Recording
A Resolver that forwards to another and records each call, in order.
Report
The failures of a check, one line each: <check>: <case>: <what>, where <check> is lazy_calls, unavailable, bytes, asof (or setup, if the embedded fixtures could not be read, which the crate’s tests rule out).
Version
A version of a stored cell: from tx on, the cell’s value is that of the receipt.

Enums§

Call
A call made to a Resolver, as Recording records it.