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

nordisk/monetize

crates/monetize-server/src/estate_order/tests/update_offer.rs

//! ★ **The Sites page's update offer** (owner 2026-10-17, test2 live): an estate that runs the
//! release sold now is UP TO DATE and offered no button; the button is offered only for a newer
//! release that carries a way to update every box (a keep medium, or a live app while live is
//! on), and when not, why — in plain words, no internal names; each box has a line, the front
//! that never asked for an update says so; a release is named by its note, not its hash.

use super::*;

#[test]
fn an_estate_on_the_release_sold_is_up_to_date_and_offered_nothing() {
    let r = delivered("offer-current", release_cfg("02", true));
    let cfg = r.state.estates.cfg.clone().unwrap();
    let run = r.state.estates.get("acme").unwrap();
    let o = update::offer(&run, &cfg);
    assert!(o.up_to_date && !o.offered, "{o:?}");
    assert_eq!(
        o.boxes
            .iter()
            .map(|b| (b.role.as_str(), b.state.as_str()))
            .collect::<Vec<_>>(),
        vec![
            ("twin", "current"),
            ("main", "current"),
            ("front", "current")
        ],
        "{o:?}"
    );
    // The refusal a press would get says it plainly.
    let e = update::start(&r.state, "acme", "", "operator").unwrap_err();
    assert!(
        matches!(&e, sold::SoldRefusal::Refused(w) if w.contains("up to date") && !w.contains('`')),
        "{e:?}"
    );
}

#[test]
fn a_newer_release_is_offered_only_when_it_carries_a_way_for_every_box() {
    let r = delivered("offer-newer", release_cfg("02", true));
    laid_older(&r);
    let mut cfg = r.state.estates.cfg.clone().unwrap();
    let run = r.state.estates.get("acme").unwrap();
    let o = update::offer(&run, &cfg);
    assert!(!o.up_to_date && o.offered && o.why_not.is_empty(), "{o:?}");
    assert!(
        o.boxes
            .iter()
            .all(|b| b.state == "behind" && b.words.contains("00-old")),
        "{o:?}"
    );
    // No keep medium and no live app: nothing offered, said plainly.
    cfg.media.remove(KEEP_MEDIUM);
    cfg.live_apps.clear();
    let o = update::offer(&run, &cfg);
    assert!(!o.up_to_date && !o.offered, "{o:?}");
    assert!(
        o.why_not
            .starts_with("No newer release with update media is published yet")
            && !o.why_not.contains('`')
            && !o.why_not.contains("gunnar-keep"),
        "{}",
        o.why_not
    );
}

#[test]
fn a_box_that_never_reported_says_so_and_the_front_says_the_update_starts_with_it() {
    let r = delivered("offer-unreported", release_cfg("02", true));
    let cfg = r.state.estates.cfg.clone().unwrap();
    let mut run = r.state.estates.get("acme").unwrap();
    run.release_of.remove("front");
    run.update_taken_at_ms = 0;
    let o = update::offer(&run, &cfg);
    let front = o
        .boxes
        .iter()
        .find(|b| b.role == "front")
        .expect("every role has a line");
    assert_eq!(front.state, "not-reported");
    assert_eq!(
        front.words,
        "not reported yet — the front has no update taker yet; the update starts with the front"
    );
    run.release_of.remove("twin");
    let o = update::offer(&run, &cfg);
    assert_eq!(
        o.boxes.iter().find(|b| b.role == "twin").unwrap().words,
        "not reported yet"
    );
}

#[test]
fn a_release_is_named_by_its_note() {
    let mut cfg = release_cfg("02", true);
    assert_eq!(
        update::release_name(&cfg, "02-gunnar"),
        "",
        "no note: the page shows the short id"
    );
    cfg.release_notes.insert(
        "02-gunnar".into(),
        update::ReleaseNote {
            label: "r5.4".into(),
            built: "2026-10-17".into(),
            carries: [
                ("gunnar".to_string(), "aa14357b1234".to_string()),
                ("gunnar-ui".to_string(), "f4b5d44abc".to_string()),
            ]
            .into(),
        },
    );
    assert_eq!(
        update::release_name(&cfg, "02-gunnar"),
        "r5.4 · 2026-10-17 · gunnar aa14357 · gunnar-ui f4b5d44"
    );
}

/// ★ **A release fed after the start is named** (owner 2026-10-18: test2's page said only
/// "e7fad415b19a"): a site's `[estates.<site>.orders]` carries `release_notes` beside its media
/// (read live; the shop's `[estate_orders]` is read only at a start), and the site's terms name
/// the release by them; the site's terms, media and notes go over the shop's.
#[test]
fn a_sites_own_release_notes_name_the_release_its_terms_sell() {
    let o: crate::config::SiteOrders = toml::from_str(&format!("term_days = 1\n[media_objects.gunnar]\nurl = \"https://objsto.example/release/gunnar/e7.iso\"\nsha256 = \"{a}\"\nbytes = 9\n[release_notes.\"{a}\"]\nlabel = \"r5.4 N\"\nbuilt = \"2026-10-17\"\ncarries = {{ gunnar = \"f16173ef\" }}\n", a = "e".repeat(64))).expect("a site's orders take release notes");
    let mut c = release_cfg("02", true);
    apply_site_orders(&mut c, &o);
    assert_eq!(c.term_days, 1);
    assert_eq!(
        super::release_id(&c, "gunnar"),
        "e".repeat(64),
        "the site's media"
    );
    assert_eq!(
        update::release_name(&c, &"e".repeat(64)),
        "r5.4 N · 2026-10-17 · gunnar f16173e"
    );
}