liminal-server 0.24.1

Standalone server for the liminal messaging bus
Documentation
//! Checkpoint audit reservations retain exact sequence and capacity authority.

use std::collections::BTreeMap;
use std::error::Error;

use super::fenced_attach_terminal::{ComposedTerminalRestoreParts, ComposedTerminalValidation};

#[test]
fn checkpoint_audit_restores_exact_reservations_through_served_codec() -> Result<(), Box<dyn Error>>
{
    let pairs = BTreeMap::from([(2, 5), (3, 8)]);
    let parts = ComposedTerminalRestoreParts::from_reservations(pairs);
    let owner = ComposedTerminalValidation::from_restore_parts(parts, 2, 8)?;
    assert_eq!(
        owner.encode_checkpoint()?,
        reservation_bytes(&[(2, 5), (3, 8)])
    );
    let restored =
        ComposedTerminalValidation::decode_checkpoint(&owner.encode_checkpoint()?, 2, 8)?;
    assert_eq!(restored.active_reservation_count(), 2);
    assert_eq!(
        restored.encode_checkpoint()?,
        reservation_bytes(&[(2, 5), (3, 8)])
    );
    Ok(())
}

#[test]
fn checkpoint_audit_refuses_uncovered_reversed_and_duplicate_sources() {
    for pairs in [
        BTreeMap::from([(2, 9)]),
        BTreeMap::from([(5, 5)]),
        BTreeMap::from([(6, 5)]),
        BTreeMap::from([(2, 8), (3, 8)]),
    ] {
        let parts = ComposedTerminalRestoreParts::from_reservations(pairs);
        assert!(ComposedTerminalValidation::from_restore_parts(parts, 2, 8).is_err());
    }
}

#[test]
fn checkpoint_audit_uses_current_capacity_instead_of_the_saved_configuration() {
    let parts = ComposedTerminalRestoreParts::from_reservations(BTreeMap::from([(2, 5), (3, 8)]));
    assert!(ComposedTerminalValidation::from_restore_parts(parts, 1, 8).is_err());
}

#[test]
fn borrowed_audit_checkpoint_keeps_owner_and_restores_the_same_pairs() -> Result<(), Box<dyn Error>>
{
    let owner = ComposedTerminalValidation::from_restore_parts(
        ComposedTerminalRestoreParts::from_reservations(BTreeMap::from([(2, 5), (3, 8)])),
        2,
        8,
    )?;
    let borrowed = owner.encode_checkpoint()?;
    let restored = ComposedTerminalValidation::decode_checkpoint(&borrowed, 2, 8)?;
    assert_eq!(borrowed, restored.encode_checkpoint()?);
    assert_eq!(owner.active_reservation_count(), 2);
    Ok(())
}

#[test]
fn audit_checkpoint_round_trip_retains_exact_pairs_and_refuses_trailing_bytes()
-> Result<(), Box<dyn Error>> {
    let owner = ComposedTerminalValidation::from_restore_parts(
        ComposedTerminalRestoreParts::from_reservations(BTreeMap::from([(2, 5), (3, 8)])),
        2,
        8,
    )?;
    let bytes = owner.encode_checkpoint()?;
    let restored = ComposedTerminalValidation::decode_checkpoint(&bytes, 2, 8)?;
    assert_eq!(restored.encode_checkpoint()?, owner.encode_checkpoint()?);
    assert_eq!(restored.encode_checkpoint()?, bytes);
    assert!(ComposedTerminalValidation::decode_checkpoint(&bytes, 1, 8).is_err());
    assert!(ComposedTerminalValidation::decode_checkpoint(&bytes, 2, 7).is_err());
    let mut trailing = bytes;
    trailing.push(0);
    assert!(ComposedTerminalValidation::decode_checkpoint(&trailing, 2, 8).is_err());
    Ok(())
}

#[test]
fn audit_checkpoint_refuses_duplicate_and_reversed_pending_keys() {
    for pairs in [[(2_u64, 5_u64), (2, 8)], [(3, 8), (2, 5)]] {
        let mut bytes = 2_u32.to_le_bytes().to_vec();
        for (pending, recovered) in pairs {
            bytes.extend_from_slice(&pending.to_le_bytes());
            bytes.extend_from_slice(&recovered.to_le_bytes());
        }
        assert!(ComposedTerminalValidation::decode_checkpoint(&bytes, 2, 8).is_err());
    }
}

fn reservation_bytes(pairs: &[(u64, u64)]) -> Vec<u8> {
    let mut bytes = 2_u32.to_le_bytes().to_vec();
    for (pending, recovered) in pairs {
        bytes.extend_from_slice(&pending.to_le_bytes());
        bytes.extend_from_slice(&recovered.to_le_bytes());
    }
    bytes
}