Your browser sucks, JavaScript disabled! Gunnar's console needs JavaScript and WebAssembly. Git over SSH on port 2222 does not.

nordisk/holger

server/lib/src/topology/tests.rs

//! The estate board's words (lane E3). The board is data (Holger v2.0 H2): its drawing
//! and the drawing's golden files are holger-ui's (`src/board.rs`).

use super::*;

const NOW: i64 = 1_790_000_000_000;

fn paired(name: &str, role: &str, overlay: [u8; 4], utility: Option<[u8; 4]>) -> PairedBox {
    PairedBox {
        name: name.into(),
        role: role.into(),
        overlay: Some(overlay.into()),
        utility: utility.map(Ipv4Addr::from),
    }
}

fn estate() -> Pairing {
    Pairing {
        estate: "test3".into(),
        me: "main".into(),
        boxes: vec![
            paired("front", ROLE_FRONT, [10, 77, 0, 1], None),
            paired("main", ROLE_PRIMARY, [10, 77, 0, 2], Some([10, 13, 8, 121])),
            paired("twin", ROLE_TWIN, [10, 77, 0, 3], Some([10, 13, 8, 122])),
        ],
        not_after_unix: 0,
    }
}

fn twin_row(state: &str, lag: u64, seen_ago_ms: u64) -> gpb::TwinRow {
    gpb::TwinRow {
        principal: "holger-twin".into(),
        address: "10.77.0.3:50051".into(),
        state: state.into(),
        last_seen_unix_ms: NOW - seen_ago_ms as i64,
        lag_entries: lag,
        disk_total_bytes: 40 << 30,
        disk_used_bytes: 9 << 30,
        applied_seq: 1000 - lag,
        head_seq: 1000,
        seen_ago_ms,
        ..Default::default()
    }
}

fn downstream(state: &str, lag: u64) -> gpb::DownstreamRow {
    gpb::DownstreamRow {
        name: "lab-holger".into(),
        state: state.into(),
        lag_entries: lag,
        last_seen_unix_ms: NOW - 20_000,
        seen_ago_ms: 20_000,
        ..Default::default()
    }
}

/// The main's view of a whole estate: the twin follows level, a downstream keeps up.
fn healthy_main() -> Facts {
    Facts {
        now_ms: NOW,
        host: "holger-main".into(),
        is_twin: false,
        own_disk: Some((40 << 30, 12 << 30)),
        own_overlay: Some([10, 77, 0, 2].into()),
        cert_not_after_unix: NOW / 1000 + 170 * 86_400,
        twins: vec![twin_row("ok", 0, 30_000)],
        downstreams: vec![downstream("ok", 0)],
        pairing: Some(estate()),
        ..Default::default()
    }
}

fn row<'a>(r: &'a pb::TopologyReply, name: &str) -> &'a pb::TopologyBox {
    r.boxes
        .iter()
        .find(|b| b.name == name)
        .unwrap_or_else(|| panic!("no box `{name}`: {:#?}", r.boxes))
}

#[test]
fn a_healthy_estate_is_three_lit_boxes_and_a_downstream_drawn_as_committed() {
    let r = board(&healthy_main());
    let names: Vec<&str> = r.boxes.iter().map(|b| b.name.as_str()).collect();
    assert_eq!(
        names,
        vec!["main", "front", "twin", "lab-holger"],
        "this box first, then front, primary, twins, downstreams"
    );
    assert_eq!(r.estate, "test3");
    assert_eq!(r.silent_after_ms, SILENT_AFTER_MS);

    let main = row(&r, "main");
    assert!(
        main.this_box && main.state == STATE_UP && !main.held,
        "{main:?}"
    );
    assert_eq!(
        (main.overlay_address.as_str(), main.utility_address.as_str()),
        ("10.77.0.2", "10.13.8.121")
    );
    assert!(main.disk_measured && main.disk_total_bytes == 40 << 30);
    let twin = row(&r, "twin");
    assert_eq!(
        (
            twin.state.as_str(),
            twin.headline.as_str(),
            twin.twin_state.as_str(),
            twin.lag_entries
        ),
        (STATE_UP, "following", "ok", 0)
    );
    assert_eq!(
        twin.overlay_address, "10.77.0.3",
        "the WireGuard overlay address rides the row"
    );
    assert!(
        twin.sources.contains(&SOURCE_PAIRING.to_string())
            && twin.sources.contains(&SOURCE_REPORT.to_string()),
        "{:?}",
        twin.sources
    );
    let front = row(&r, "front");
    assert_eq!(
        (front.state.as_str(), front.headline.as_str()),
        (STATE_UNKNOWN, "not asked"),
        "nothing here asks the front: unknown, never silent"
    );
    assert_eq!(row(&r, "lab-holger").role, ROLE_DOWNSTREAM);

    let links: Vec<(&str, &str, &str, &str)> = r
        .links
        .iter()
        .map(|l| {
            (
                l.from.as_str(),
                l.to.as_str(),
                l.kind.as_str(),
                l.state.as_str(),
            )
        })
        .collect();
    assert_eq!(
        links,
        vec![
            ("front", "main", LINK_SERVES, STATE_UP),
            ("main", "twin", LINK_FOLLOWS, STATE_UP),
            ("main", "lab-holger", LINK_PULLS, STATE_UP)
        ]
    );

    for (name, state) in [
        ("main", "up"),
        ("twin", "up"),
        ("front", "unknown"),
        ("lab-holger", "up"),
    ] {
        assert_eq!(row(&r, name).state, state, "{name} not {state}");
    }
}

/// ★ **The board is data** (Holger v2.0 H2 #1): the server decides every word and
/// draws nothing. holger-ui draws the rows; no server build links a renderer.
#[test]
fn the_server_serves_the_board_and_draws_nothing() {
    let r = board(&whole_estate());
    assert!(
        r.svg.is_empty(),
        "the server drew the board: {}",
        &r.svg[..r.svg.len().min(200)]
    );
}

#[test]
fn a_lagging_twin_is_drawn_lagging() {
    let mut f = healthy_main();
    f.twins = vec![twin_row("behind", 120, 30_000)];
    let r = board(&f);
    let twin = row(&r, "twin");
    assert_eq!(
        (
            twin.state.as_str(),
            twin.headline.as_str(),
            twin.twin_state.as_str(),
            twin.lag_entries
        ),
        (STATE_BEHIND, "behind 120 entries", "behind", 120)
    );
    assert_eq!(
        r.links
            .iter()
            .find(|l| l.to == "twin")
            .map(|l| l.state.as_str()),
        Some(STATE_BEHIND),
        "the link into the twin carries its state"
    );

    // A twin whose position stopped while the head moved is lagging too, and says so.
    f.twins = vec![twin_row("stalled", 40, 30_000)];
    let r = board(&f);
    assert_eq!(
        (
            row(&r, "twin").state.as_str(),
            row(&r, "twin").headline.as_str()
        ),
        (STATE_BEHIND, "stalled, behind 40 entries")
    );
}

#[test]
fn a_silent_twin_and_one_never_heard_are_dark_and_say_which() {
    let mut f = healthy_main();
    f.twins = vec![twin_row("silent", 3, 240_000)];
    let r = board(&f);
    assert_eq!(
        (
            row(&r, "twin").state.as_str(),
            row(&r, "twin").headline.as_str()
        ),
        (STATE_SILENT, "silent for 4 min")
    );

    f.twins.clear();
    let r = board(&f);
    assert_eq!(
        (
            row(&r, "twin").state.as_str(),
            row(&r, "twin").headline.as_str()
        ),
        (STATE_SILENT, "never heard"),
        "a paired twin that never reported is still drawn"
    );
}

#[test]
fn a_dead_main_is_drawn_held() {
    // The main's own view: back up after its death, held for its recharge (M3's boot hold).
    let mut f = healthy_main();
    f.held_from = Some("twin".into());
    let r = board(&f);
    let main = row(&r, "main");
    assert!(main.held && main.state == STATE_SILENT, "{main:?}");
    assert_eq!(main.headline, "held for its recharge from twin");
    assert_eq!(
        r.links
            .iter()
            .find(|l| l.kind == LINK_SERVES)
            .map(|l| l.state.as_str()),
        Some(STATE_SILENT),
        "the front's link into a held main is dark"
    );

    // A fenced primary is held too.
    let mut f = healthy_main();
    f.fenced = Some(7);
    let main = board(&f).boxes.remove(0);
    assert!(
        main.held && main.headline == "held: fenced at epoch 7",
        "{main:?}"
    );

    // The twin's view: its primary stopped answering. Nothing is promoted; the main is held.
    let twin_view = Facts {
        now_ms: NOW,
        host: "holger-twin".into(),
        is_twin: true,
        primary_at: "10.77.0.2:50051".into(),
        look: Some(Judged {
            state: "silent",
            lag: 5,
            applied: 995,
            seen_ago_ms: 240_000,
            silent: true,
            stalled: false,
        }),
        own_overlay: Some([10, 77, 0, 3].into()),
        pairing: Some(Pairing {
            me: "twin".into(),
            ..estate()
        }),
        ..Default::default()
    };
    let r = board(&twin_view);
    assert_eq!(r.boxes[0].name, "twin");
    assert_eq!(
        (r.boxes[0].state.as_str(), r.boxes[0].headline.as_str()),
        (STATE_UP, "keeping the estate")
    );
    let main = row(&r, "main");
    assert!(
        main.held && main.state == STATE_SILENT && main.headline == "held: silent for 4 min",
        "{main:?}"
    );
}

#[test]
fn a_twin_with_a_live_primary_reports_its_own_lag() {
    let f = Facts {
        now_ms: NOW,
        is_twin: true,
        primary_at: "10.77.0.2:50051".into(),
        look: Some(Judged {
            state: "behind",
            lag: 12,
            applied: 988,
            seen_ago_ms: 5_000,
            silent: false,
            stalled: false,
        }),
        pairing: Some(Pairing {
            me: "twin".into(),
            ..estate()
        }),
        ..Default::default()
    };
    let r = board(&f);
    let me = &r.boxes[0];
    assert_eq!(
        (
            me.state.as_str(),
            me.headline.as_str(),
            me.twin_state.as_str(),
            me.lag_entries
        ),
        (STATE_BEHIND, "behind 12 entries", "behind", 12)
    );
    assert_eq!(
        (
            row(&r, "main").state.as_str(),
            row(&r, "main").headline.as_str()
        ),
        (STATE_UP, "answering")
    );
}

#[test]
fn an_unpaired_holger_is_one_box() {
    let r = board(&Facts {
        now_ms: NOW,
        host: "solo".into(),
        ..Default::default()
    });
    assert_eq!(r.boxes.len(), 1);
    assert_eq!(
        (r.boxes[0].name.as_str(), r.boxes[0].state.as_str()),
        ("solo", STATE_UP)
    );
    assert!(r.links.is_empty() && r.estate.is_empty());
}

#[test]
fn the_coarse_words_change_only_when_the_state_does() {
    assert_eq!(ago(59_999), "under a minute");
    assert_eq!(ago(60_000), "1 min");
    assert_eq!(ago(7_199_000), "119 min");
    assert_eq!(ago(7_200_000), "2 h");
}

fn upstream(
    name: &str,
    kind: &str,
    f: impl FnOnce(&mut crate::upstreams::UpstreamFact),
) -> crate::upstreams::UpstreamFact {
    let mut u = crate::upstreams::UpstreamFact {
        name: name.into(),
        kind: kind.into(),
        speaks: if kind == crate::upstreams::KIND_MIRROR {
            "Holger".into()
        } else {
            "rust-remote".into()
        },
        address: format!("https://{name}.example"),
        feeds: vec!["crates".into()],
        registered_ms: NOW - 3_600_000,
        ..Default::default()
    };
    f(&mut u);
    u
}

/// The main of the MVP estate as the owner asked for it (lane A13): its upstreams
/// above it with their state, two downstreams below with how far behind each is
/// and how many packages each fetched, and every consumer counted.
fn whole_estate() -> Facts {
    let mut f = healthy_main();
    f.upstreams = vec![
        upstream("crates-io", crate::upstreams::KIND_PROXY, |u| {
            (u.answered, u.fetched, u.last_ok_ms) = (40, 31, NOW - 20_000);
        }),
        upstream("pypi", crate::upstreams::KIND_PROXY, |u| {
            (
                u.answered,
                u.failed,
                u.last_ok_ms,
                u.last_err_ms,
                u.last_error,
            ) = (
                3,
                2,
                NOW - 900_000,
                NOW - 240_000,
                "connection refused".into(),
            );
            u.speaks = "nexus-remote".into();
            u.feeds = vec!["pip".into()];
        }),
        upstream("npmjs", crate::upstreams::KIND_PROXY, |u| {
            u.feeds = vec!["npm".into()]
        }),
        upstream("cloud", crate::upstreams::KIND_MIRROR, |u| {
            (
                u.answered,
                u.fetched,
                u.last_ok_ms,
                u.every_secs,
                u.paired_as,
                u.link,
            ) = (
                12,
                120,
                NOW - 30_000,
                60,
                "cloud-holger".into(),
                "paired".into(),
            );
            u.feeds = vec!["B".into()];
        }),
    ];
    f.downstreams = vec![
        gpb::DownstreamRow {
            fetched_total: 1_204,
            fetched_today: 17,
            ..downstream("ok", 0)
        },
        gpb::DownstreamRow {
            name: "plant-holger".into(),
            fetched_total: 88,
            fetched_today: 0,
            ..downstream("behind", 5)
        },
    ];
    f.consumers = Some(ConsumerCount {
        counted: true,
        principals: 3,
        peers: 2,
        anonymous_today: 14,
        window_days: 30,
    });
    f
}

/// ★ **The board shows where the bytes come from, how far behind each
/// downstream is and how much it fetched, and every consumer** (lane A13).
#[test]
fn the_board_draws_upstreams_downstream_fetches_and_every_consumer() {
    let r = board(&whole_estate());
    let names: Vec<&str> = r.boxes.iter().map(|b| b.name.as_str()).collect();
    assert_eq!(
        names,
        vec![
            "main",
            "front",
            "twin",
            "cloud",
            "crates-io",
            "npmjs",
            "pypi",
            "lab-holger",
            "plant-holger"
        ],
        "upstreams after the twins, before the downstreams"
    );

    let words = |n: &str| {
        let b = row(&r, n);
        (
            b.role.as_str(),
            b.state.as_str(),
            b.headline.as_str(),
            b.upstream_kind.as_str(),
            b.fetched_total,
        )
    };
    assert_eq!(
        words("crates-io"),
        (ROLE_UPSTREAM, STATE_UP, "answering", "proxy", 31)
    );
    assert_eq!(
        words("pypi"),
        (ROLE_UPSTREAM, STATE_SILENT, "failing for 4 min", "proxy", 0)
    );
    assert!(
        row(&r, "pypi").why.contains("connection refused")
            && row(&r, "pypi").why.contains("15 min ago"),
        "{}",
        row(&r, "pypi").why
    );
    assert_eq!(
        words("npmjs"),
        (
            ROLE_UPSTREAM,
            STATE_UNKNOWN,
            "not asked since boot",
            "proxy",
            0
        ),
        "declared and never asked is unknown, never silent"
    );
    assert_eq!(
        words("cloud"),
        (ROLE_UPSTREAM, STATE_UP, "syncing", "mirror", 120)
    );
    assert_eq!(
        row(&r, "cloud").sources,
        vec![SOURCE_CONFIG, SOURCE_MIRROR, SOURCE_PAIRING]
    );
    assert_eq!(
        row(&r, "crates-io").sources,
        vec![SOURCE_CONFIG, SOURCE_PROXY]
    );
    assert_eq!(row(&r, "crates-io").address, "https://crates-io.example");
    assert_eq!(row(&r, "pypi").feeds, vec!["pip"]);

    let lab = row(&r, "lab-holger");
    assert_eq!(
        (
            lab.state.as_str(),
            lab.lag_entries,
            lab.fetched_total,
            lab.fetched_today
        ),
        (STATE_UP, 0, 1_204, 17)
    );
    let plant = row(&r, "plant-holger");
    assert_eq!(
        (
            plant.state.as_str(),
            plant.headline.as_str(),
            plant.lag_entries,
            plant.fetched_total
        ),
        (STATE_BEHIND, "behind 5 entries", 5, 88)
    );

    let c = r
        .consumers
        .as_ref()
        .expect("the consumers are on the reply");
    assert_eq!(
        (
            c.counted,
            c.principals,
            c.peers,
            c.anonymous_today,
            c.window_days
        ),
        (true, 3, 2, 14, 30)
    );

    let feeds: Vec<(&str, &str, &str)> = r
        .links
        .iter()
        .filter(|l| l.kind == LINK_FEEDS)
        .map(|l| (l.from.as_str(), l.to.as_str(), l.state.as_str()))
        .collect();
    assert_eq!(
        feeds,
        vec![
            ("cloud", "main", STATE_UP),
            ("crates-io", "main", STATE_UP),
            ("npmjs", "main", STATE_UNKNOWN),
            ("pypi", "main", STATE_SILENT)
        ],
        "each upstream feeds the main, with its own state"
    );

    // The same board as JSON (`GET /-/estate.json`): the rows in order, with their words.
    let v = json(&r);
    let names_json: Vec<&str> = v["boxes"]
        .as_array()
        .unwrap()
        .iter()
        .filter_map(|b| b["name"].as_str())
        .collect();
    assert_eq!(
        names_json, names,
        "the JSON door serves the same rows in the same order"
    );
    assert_eq!(v["boxes"][6]["headline"], "failing for 4 min");
    assert_eq!(v["boxes"][6]["state"], STATE_SILENT);
    assert_eq!(v["links"].as_array().unwrap().len(), r.links.len());
    assert_eq!(v["consumers"]["anonymous_today"], 14);
    assert_eq!(v["summary"], r.summary.as_str());
    assert!(
        r.summary
            .starts_with("3 boxes: front, main, twin · 4 upstreams"),
        "{}",
        r.summary
    );
}

/// ★ A build with no book says so, and never shows a 0 it did not count.
#[test]
fn a_build_without_a_book_says_its_consumers_are_not_counted() {
    let r = board(&healthy_main());
    assert!(r.consumers.is_none());
    assert!(
        r.summary.contains("consumers not counted in this build")
            && !r.summary.contains("consumers: 0"),
        "{}",
        r.summary
    );
    assert!(json(&r)["consumers"].is_null());
}

/// ★ A mirror's words: a key mismatch, a quiet one, one that keeps failing.
#[test]
fn a_mirrored_holger_says_key_mismatch_silent_or_failing() {
    let m = |f: fn(&mut crate::upstreams::UpstreamFact)| {
        upstream_words(
            &upstream("cloud", crate::upstreams::KIND_MIRROR, |u| {
                (u.every_secs, u.last_ok_ms, u.paired_as) =
                    (60, NOW - 30_000, "cloud-holger".into());
                f(u)
            }),
            NOW,
        )
    };
    assert_eq!(m(|u| u.link = "key-mismatch".into()).0, STATE_SILENT);
    assert_eq!(m(|u| u.link = "key-mismatch".into()).1, "key mismatch");
    assert_eq!(
        (
            m(|u| u.last_ok_ms = NOW - 600_000).0,
            m(|u| u.last_ok_ms = NOW - 600_000).1
        ),
        (STATE_SILENT, "silent for 10 min".to_string())
    );
    assert_eq!(
        (
            m(|u| u.consecutive_failures = 2).0,
            m(|u| u.consecutive_failures = 2).1
        ),
        (STATE_BEHIND, "2 failed cycles".to_string())
    );
    assert_eq!(m(|u| u.last_ok_ms = 0).0, STATE_UNKNOWN);
    assert_eq!(
        (
            m(|u| (u.last_ok_ms, u.failed) = (0, 3)).0,
            m(|u| (u.last_ok_ms, u.failed) = (0, 3)).1
        ),
        (STATE_SILENT, "never synced".to_string())
    );
}

// ── the RON's own graph (HBOARD-1, owner 2026-10-23: sources, downstreams, counts, lag) ──

/// A declaration's text, read the way `holger-server start --config` reads it.
fn holger_of(ron: &str) -> crate::Holger {
    let mut f = tempfile::NamedTempFile::new().unwrap();
    std::io::Write::write_all(&mut f, ron.as_bytes()).unwrap();
    match crate::read_ron_config(f.path()) {
        Ok(h) => h,
        Err(e) => panic!("the fixture declaration must parse: {e:#}"),
    }
}

/// Two upstream sources and an upload door, the way tier 1's `sources:` spells them.
const RON_SOURCES: &str = r#"(
    repositories: [
        (ron_name: "cargo", ron_repo_type: "rust", ron_upstreams: [], ron_in: None, ron_out: None),
        (ron_name: "incoming", ron_repo_type: "raw", ron_upstreams: [], ron_in: None, ron_out: None),
    ],
    exposed_endpoints: [],
    storage_endpoints: [],
    sources: [
        (name: "crates-io", kind: crates, serves: ["cargo"]),
        (name: "cloud", kind: holger, url: "http://10.77.0.9:50051", repositories: [(ron_from: "cargo", ron_to: "cargo")]),
        (name: "team", kind: upload),
    ],
)"#;

/// ★ **The board is the RON's graph**: every source the declaration names is a row, with
/// its address and the repositories it feeds, before anything has walked to it; what a
/// walk learnt (the fetched count) lands on the declared row.
#[test]
fn every_declared_source_is_on_the_board_with_its_count() {
    let h = holger_of(RON_SOURCES);
    let d = declared(&h);
    let names: Vec<&str> = d.upstreams.iter().map(|u| u.name.as_str()).collect();
    assert_eq!(
        names,
        vec!["cloud", "crates-io", "team"],
        "each declared source, by name"
    );

    let fetched = crate::upstreams::UpstreamFact {
        name: "crates-io".into(),
        kind: crate::upstreams::KIND_PROXY.into(),
        feeds: vec!["cargo".into()],
        fetched: 7,
        answered: 9,
        last_ok_ms: NOW - 60_000,
        ..Default::default()
    };
    let r = board(&Facts {
        now_ms: NOW,
        host: "main".into(),
        declared: d,
        upstreams: vec![fetched],
        ..Default::default()
    });
    let row = |n: &str| {
        r.boxes.iter().find(|b| b.name == n).unwrap_or_else(|| {
            panic!(
                "{n} is not on the board: {:?}",
                r.boxes.iter().map(|b| &b.name).collect::<Vec<_>>()
            )
        })
    };
    for n in ["cloud", "crates-io", "team"] {
        assert_eq!(row(n).role, ROLE_UPSTREAM, "{n} is an upstream row");
    }
    assert_eq!(
        r.boxes.iter().filter(|b| b.name == "crates-io").count(),
        1,
        "the declared row and its evidence are ONE row"
    );
    assert_eq!(
        row("crates-io").fetched_total,
        7,
        "the walk's count lands on the declared row"
    );
    assert_eq!(row("crates-io").feeds, vec!["cargo".to_string()]);
    assert_eq!(row("cloud").upstream_kind, crate::upstreams::KIND_MIRROR);
    assert_eq!(row("cloud").address, "http://10.77.0.9:50051");
    assert_eq!(
        row("cloud").state,
        STATE_UNKNOWN,
        "declared, no cycle yet: never a made-up 'up'"
    );
    assert_eq!(row("team").upstream_kind, crate::upstreams::KIND_UPLOAD);
    assert_eq!(row("team").feeds, vec!["incoming".to_string()]);
    assert!(
        r.summary
            .contains("2 upstreams: cloud, crates-io, and uploads"),
        "{}",
        r.summary
    );
    let feeds = r.links.iter().filter(|l| l.kind == LINK_FEEDS).count();
    assert_eq!(feeds, 3, "each source feeds the main");
}

/// ★ A laid estate's own declaration (holger-recipe's medium: the intake chain, no
/// `sources:`) still says where its packages come in: the uploads into `incoming`.
#[test]
fn an_estate_with_no_sources_shows_its_upload_door() {
    let h = holger_of(
        r#"(
        repositories: [(ron_name: "incoming", ron_repo_type: "raw", ron_upstreams: [], ron_in: None, ron_out: None)],
        exposed_endpoints: [],
        storage_endpoints: [],
    )"#,
    );
    let d = declared(&h);
    assert_eq!(d.upstreams.len(), 1);
    assert_eq!(
        (d.upstreams[0].name.as_str(), d.upstreams[0].kind.as_str()),
        ("uploads", crate::upstreams::KIND_UPLOAD)
    );
    let r = board(&Facts {
        now_ms: NOW,
        host: "main".into(),
        declared: d,
        ..Default::default()
    });
    assert!(r
        .boxes
        .iter()
        .any(|b| b.name == "uploads" && b.role == ROLE_UPSTREAM && b.state == STATE_UP));
}

/// ★ **The downstream connector the RON declares** (`sync.downstreams`) is a downstream row,
/// with the lag its sync board measures, in the board's own words.
#[cfg(feature = "sync")]
#[test]
fn a_declared_sync_downstream_is_on_the_board_with_its_lag() {
    let h = holger_of(&RON_SOURCES.replace(
        "    sources: [",
        &format!("    sync: Some((name: \"main\", downstreams: [(name: \"lab-holger\", key: \"{}\")])),\n    sources: [", "ab".repeat(32)),
    ));
    let d = declared(&h);
    assert_eq!(d.downstreams, vec!["lab-holger".to_string()]);
    let lag = SyncDownstream {
        name: "lab-holger".into(),
        via: "wireguard".into(),
        state: "behind".into(),
        headline: "2 generations behind".into(),
        lag_generations: 2,
        lag_secs: 600,
        last_generation_applied: 3,
        ..Default::default()
    };
    let consumers = ConsumerCount {
        counted: true,
        principals: 3,
        peers: 1,
        anonymous_today: 5,
        window_days: 30,
    };
    let r = board(&Facts {
        now_ms: NOW,
        host: "main".into(),
        declared: d,
        sync: vec![lag],
        consumers: Some(consumers),
        ..Default::default()
    });
    let down = r
        .boxes
        .iter()
        .find(|b| b.name == "lab-holger")
        .expect("the declared downstream is on the board");
    assert_eq!(down.role, ROLE_DOWNSTREAM);
    assert_eq!(down.state, STATE_BEHIND);
    assert_eq!(
        down.lag_entries, 2,
        "its lag, as the sync board measured it"
    );
    assert_eq!(down.headline, "2 generations behind");
    assert!(r
        .links
        .iter()
        .any(|l| l.kind == LINK_PULLS && l.to == "lab-holger"));
    assert!(
        r.summary
            .contains("1 downstream: lab-holger via wireguard 10 min behind")
            && r.summary
                .contains("3 people and 1 machine used it in 30 days, 5 anonymous today"),
        "{}",
        r.summary
    );
    // ★ Lane HOL-WGDS: the board and the summary line say how it reaches this holger, and its lag.
    assert_eq!(down.via, "wireguard");
    // A downstream the console enrolled (not in the RON) is on the board too, from the sync board's rows.
    let console = SyncDownstream {
        name: "lab-1".into(),
        via: "front".into(),
        state: "current".into(),
        headline: "at generation 3".into(),
        last_generation_applied: 3,
        ..Default::default()
    };
    let r = board(&Facts {
        now_ms: NOW,
        host: "main".into(),
        declared: declared(&h),
        sync: vec![console],
        ..Default::default()
    });
    let lab1 = r
        .boxes
        .iter()
        .find(|b| b.name == "lab-1")
        .expect("a console-enrolled downstream is drawn");
    assert_eq!(
        (lab1.role.as_str(), lab1.via.as_str()),
        (ROLE_DOWNSTREAM, "front")
    );
    assert!(r.summary.contains("lab-1 via front"), "{}", r.summary);
    // Never heard: still on the board, in its own word.
    let r = board(&Facts {
        now_ms: NOW,
        host: "main".into(),
        declared: declared(&h),
        ..Default::default()
    });
    let down = r
        .boxes
        .iter()
        .find(|b| b.name == "lab-holger")
        .expect("declared, not measured: still drawn");
    assert_eq!(down.state, STATE_UNKNOWN);
}

/// holger.rs as it is (the owner's board, 2026-10-27): front, main and twin, the uploads into
/// `incoming` and no `sources:`, no downstream, one person in the window.
fn holger_rs() -> Facts {
    let mut f = healthy_main();
    f.downstreams = Vec::new();
    f.declared = Declared {
        upstreams: vec![DeclaredUpstream {
            name: UPLOADS.into(),
            kind: crate::upstreams::KIND_UPLOAD.into(),
            speaks: "upload".into(),
            address: String::new(),
            feeds: vec![UPLOAD_DOOR.into()],
        }],
        downstreams: Vec::new(),
        fetch: Vec::new(),
    };
    f.consumers = Some(ConsumerCount {
        counted: true,
        principals: 1,
        peers: 0,
        anonymous_today: 0,
        window_days: 30,
    });
    f
}

/// ★ **The line under the title is plain and true** (OX-HOLF, the owner on holger.rs's
/// board): it counts the estate's boxes and names them (an upstream or a downstream is no
/// box of this estate), says there is no upstream when the only way in is the uploads, names
/// every downstream with its last sync or its lag (or says there is none), and says who used
/// it in the window.
#[test]
fn the_line_names_the_boxes_the_upstreams_the_downstreams_and_who_used_it() {
    assert_eq!(
        board(&holger_rs()).summary,
        "3 boxes: front, main, twin · no upstream (uploads only) · no downstream · 1 person used it in 30 days"
    );
    assert_eq!(
        board(&whole_estate()).summary,
        "3 boxes: front, main, twin · 4 upstreams: cloud, crates-io, npmjs, pypi · 2 downstreams: lab-holger via front synced under a minute ago, plant-holger via front 5 entries behind · 3 people and 2 machines used it in 30 days, 14 anonymous today"
    );
}

/// ★ The downstreams the RON declares (`sync.downstreams`), each with its last sync or its
/// lag, as the sync board measures them.
#[cfg(feature = "sync")]
#[test]
fn the_line_names_each_declared_downstream_with_its_last_sync_or_its_lag() {
    let mut f = holger_rs();
    f.declared.downstreams = vec!["lab-1".into(), "lab-2".into(), "lab-3".into()];
    let now = NOW / 1000;
    f.sync = vec![
        SyncDownstream {
            name: "lab-1".into(),
            state: "current".into(),
            last_generation_applied: 9,
            last_ack_at: now - 7_200,
            ..Default::default()
        },
        SyncDownstream {
            name: "lab-2".into(),
            state: "behind".into(),
            lag_generations: 2,
            lag_secs: 3 * 86_400,
            last_ack_at: now - 3 * 86_400 - 60,
            ..Default::default()
        },
    ];
    let r = board(&f);
    assert_eq!(
        r.summary,
        "3 boxes: front, main, twin · no upstream (uploads only) · 3 downstreams: lab-1 via front synced 2 h ago, lab-2 via front 3 days behind, lab-3 via front never synced · 1 person used it in 30 days"
    );
    assert_eq!(
        row(&r, "lab-1").last_seen_unix_ms,
        NOW - 7_200_000,
        "the row carries the last sync the line names"
    );
}

/// ★ Lane OX-WGDS2: a sync downstream whose acknowledgements never come by the net (a
/// `downstream` build acks by stick) is measured by its mirror's signed report: the row and
/// the line say when it last synced and how many writes it is behind, never "never".
#[cfg(feature = "sync")]
#[test]
fn a_sync_downstream_heard_by_its_mirrors_report_says_its_last_sync_and_its_lag() {
    let mut f = holger_rs();
    f.declared.downstreams = vec!["lab-1".into(), "lab-2".into()];
    let now = NOW / 1000;
    f.sync = vec![
        SyncDownstream {
            name: "lab-1".into(),
            via: "front".into(),
            state: "current".into(),
            last_report_at: now - 120,
            ..Default::default()
        },
        SyncDownstream {
            name: "lab-2".into(),
            via: "wireguard".into(),
            state: "behind".into(),
            last_report_at: now - 30,
            entries_behind: 4,
            ..Default::default()
        },
    ];
    let r = board(&f);
    assert!(
        r.summary.contains(
            "2 downstreams: lab-1 via front synced 2 min ago, lab-2 via wireguard 4 entries behind"
        ),
        "{}",
        r.summary
    );
    let (l1, l2) = (row(&r, "lab-1"), row(&r, "lab-2"));
    assert_eq!(
        (l1.state.as_str(), l1.last_seen_unix_ms),
        (STATE_UP, NOW - 120_000),
        "its last report is when it was last seen"
    );
    assert_eq!(
        (l2.state.as_str(), l2.lag_entries, l2.last_seen_unix_ms),
        (STATE_BEHIND, 4, NOW - 30_000)
    );
}

/// ★ **The line and the drawing never disagree**: both are the same rows. Every count and
/// every name the line says is the rows holger-ui draws.
#[test]
fn the_line_counts_the_rows_the_board_draws() {
    let mut fixtures = vec![holger_rs(), whole_estate(), healthy_main()];
    let mut two_twins = whole_estate();
    two_twins.twins.push(gpb::TwinRow {
        principal: "twin-2".into(),
        address: "10.77.0.4:50051".into(),
        ..twin_row("ok", 0, 1_000)
    });
    fixtures.push(two_twins);
    for f in fixtures {
        let r = board(&f);
        let rows = |role: &str| {
            r.boxes
                .iter()
                .filter(|b| b.role == role)
                .collect::<Vec<_>>()
        };
        let boxes = rows(ROLE_FRONT).len() + rows(ROLE_PRIMARY).len() + rows(ROLE_TWIN).len();
        assert!(
            r.summary.starts_with(&format!("{boxes} box")),
            "{boxes} estate rows drawn: {}",
            r.summary
        );
        let ups: Vec<_> = rows(ROLE_UPSTREAM)
            .into_iter()
            .filter(|b| b.upstream_kind != crate::upstreams::KIND_UPLOAD)
            .collect();
        match ups.len() {
            0 => assert!(r.summary.contains(" · no upstream"), "{}", r.summary),
            n => assert!(
                r.summary.contains(&format!(" · {n} upstream"))
                    && ups.iter().all(|u| r.summary.contains(&u.name)),
                "{}",
                r.summary
            ),
        }
        let downs = rows(ROLE_DOWNSTREAM);
        match downs.len() {
            0 => assert!(r.summary.contains(" · no downstream"), "{}", r.summary),
            n => assert!(
                r.summary.contains(&format!(" · {n} downstream"))
                    && downs.iter().all(|d| r.summary.contains(&d.name)),
                "{}",
                r.summary
            ),
        }
    }
}