haematite-cli 0.21.1

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::sync::{Arc, Barrier};

use super::limits::Limit;

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

#[test]
fn admission_refuses_over_capacity_and_releases_only_its_owned_permit() -> TestResult {
    let limit = Arc::new(Limit::new(1));
    let held = limit.enter().ok_or("first permit missing")?;
    assert!(limit.enter().is_none());
    drop(held);
    let next = limit.enter().ok_or("released permit missing")?;
    assert!(limit.enter().is_none());
    drop(next);
    Ok(())
}

#[test]
fn concurrent_admission_never_exceeds_the_configured_bound() -> TestResult {
    let limit = Arc::new(Limit::new(1));
    let start = Arc::new(Barrier::new(3));
    let finish = Arc::new(Barrier::new(3));
    let mut tasks = Vec::new();
    for _ in 0..2 {
        let limit = Arc::clone(&limit);
        let start = Arc::clone(&start);
        let finish = Arc::clone(&finish);
        tasks.push(std::thread::spawn(move || {
            start.wait();
            let permit = limit.enter();
            let admitted = permit.is_some();
            finish.wait();
            drop(permit);
            admitted
        }));
    }
    start.wait();
    finish.wait();
    let mut admitted = 0;
    for task in tasks {
        admitted += usize::from(task.join().map_err(|_| "admission task panicked")?);
    }
    assert_eq!(admitted, 1);
    assert!(limit.enter().is_some());
    Ok(())
}