liminal-server 0.25.4

Standalone server for the liminal messaging bus
Documentation
//! SRV-038 R3: `/health` carries the network-root answer; `/ready` does not
//! change with it.

use super::*;
use crate::auth_lys::root_presence::{LysRoot, RootPresence};
use crate::auth_lys::root_presence_start::RootSlot;

fn answered(
    runtime: &tokio::runtime::Runtime,
    answer: LysRoot,
) -> Result<(ServedState, Arc<RootPresence>), Box<dyn std::error::Error>> {
    let state = served(SharedReadinessState::new(
        ReadinessState::ready_without_cluster(),
    ));
    // Never asked here: the answer is recorded directly, so the address is unused.
    let presence = Arc::new(RootPresence::new(
        "ablative",
        "https://lys.invalid/api/",
        "health-fixture-credential".to_owned(),
        runtime.handle().clone(),
    )?);
    presence.record_for_tests(answer);
    state
        .lys_root
        .set(RootSlot::Asked(Arc::clone(&presence)))
        .map_err(|_| "lys root already installed")?;
    Ok((state, presence))
}

fn health_and_ready(state: &ServedState) -> Result<(Value, String), Box<dyn std::error::Error>> {
    let health = json_body(&String::from_utf8(response_for_request(
        b"GET /health HTTP/1.1\r\n\r\n",
        state,
    )?)?)?;
    let ready = String::from_utf8(response_for_request(b"GET /ready HTTP/1.1\r\n\r\n", state)?)?;
    Ok((health, ready))
}

#[test]
fn health_reports_lys_root() -> Result<(), Box<dyn std::error::Error>> {
    let runtime = tokio::runtime::Builder::new_current_thread()
        .enable_all()
        .build()?;
    let (absent, _) = answered(&runtime, LysRoot::Absent)?;
    let (absent_health, absent_ready) = health_and_ready(&absent)?;
    assert_eq!(absent_health["lys_root"], "absent");
    assert!(absent_health.get("lys_root_cause").is_none());

    let (held, _) = answered(&runtime, LysRoot::Held)?;
    let (held_health, held_ready) = health_and_ready(&held)?;
    assert_eq!(held_health["lys_root"], "held");
    assert_eq!(
        absent_ready, held_ready,
        "a rootless network is not unready"
    );

    let (unknown, _) = answered(
        &runtime,
        LysRoot::Unknown {
            cause: "lys_root_refused",
        },
    )?;
    let (unknown_health, _) = health_and_ready(&unknown)?;
    assert_eq!(unknown_health["lys_root"], "unknown");
    assert_eq!(unknown_health["lys_root_cause"], "lys_root_refused");

    let (not_asked, _) = answered(&runtime, LysRoot::NotAsked)?;
    assert_eq!(health_and_ready(&not_asked)?.0["lys_root"], "not_asked");

    // SRV-039 R2: a server with Lys and nothing to ask with says why.
    let unasked = served(SharedReadinessState::new(
        ReadinessState::ready_without_cluster(),
    ));
    unasked
        .lys_root
        .set(RootSlot::Unasked {
            cause: "no_asking_credential",
        })
        .map_err(|_| "lys root already installed")?;
    let unasked_health = health_and_ready(&unasked)?.0;
    assert_eq!(unasked_health["lys_root"], "not_asked");
    assert_eq!(unasked_health["lys_root_cause"], "no_asking_credential");

    let bare = served(SharedReadinessState::new(
        ReadinessState::ready_without_cluster(),
    ));
    assert!(health_and_ready(&bare)?.0["lys_root"].is_null());
    Ok(())
}