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

nordisk/monetize

crates/monetize-site-buy/tests/relay.rs

//! ★ **The relay keeps the buyer on the site** (owner 2026-10-23): every step goes to the ONE
//! monetize over the site's own bearer, every way back from the vendor is on the site, the
//! e-mail is asked once (at account creation, never in a buy), and the product vouches for a
//! signed-in buyer with its own ticket.

mod common;

use axum::http::StatusCode;
use common::{call, relay, relay_with, BEARER, ORIGIN};
use serde_json::json;

#[tokio::test]
async fn a_visitors_sign_up_goes_to_the_shop_with_the_sites_own_ways_back() {
    let (r, fake) = relay("holger").await;
    let (st, body, _) = call(&r, "POST", "/auth/signup/start", None, Some(json!({"username": "x14", "email": "ops@mock.invalid", "plan": "holger/5gb-1m", "next": "/"}))).await;
    assert_eq!(st, StatusCode::OK, "{body}");
    assert_eq!(
        body["url"],
        "https://checkout.mock.invalid/c/pay/cs_test_abcdefghijkl"
    );
    let h = fake.heard.lock().unwrap();
    let s = h.signup_start.as_ref().unwrap();
    assert_eq!(
        (
            s.username.as_str(),
            s.product.as_str(),
            s.plan.as_str(),
            s.email.as_str(),
            s.vendor.as_str()
        ),
        ("x14", "holger", "holger/5gb-1m", "ops@mock.invalid", ""),
        "A32-15: the site names no vendor: the shop routes it"
    );
    assert_eq!(
        s.success_url,
        format!("{ORIGIN}/welcome?session={{session}}&next=%2F")
    );
    assert_eq!(s.cancel_url, format!("{ORIGIN}/signup?plan=account"));
    assert!(
        h.bearers.iter().all(|b| b == &format!("Bearer {BEARER}")),
        "every call carries the site's bearer"
    );
}

#[tokio::test]
async fn the_shops_verdict_is_shown_and_a_member_buys_nothing() {
    let (r, _) = relay("holger").await;
    let (st, body, _) = call(
        &r,
        "POST",
        "/auth/signup/start",
        None,
        Some(json!({"username": "held", "email": "ops@mock.invalid"})),
    )
    .await;
    assert_eq!(st, StatusCode::CONFLICT);
    assert!(body["error"]
        .as_str()
        .unwrap()
        .starts_with("Someone is signing up with this account name"));
    let (st, body, _) = call(
        &r,
        "POST",
        "/auth/signup/start",
        Some("member:acme"),
        Some(json!({"username": "ann2", "email": "ops@mock.invalid"})),
    )
    .await;
    assert_eq!(st, StatusCode::FORBIDDEN);
    assert_eq!(
        body["error"],
        "You are a member of acme. A member buys nothing: acme's room is its admin's to buy."
    );
    let (st, body, _) = call(
        &r,
        "POST",
        "/auth/signup/start",
        None,
        Some(json!({"username": "x14", "email": "not-an-address"})),
    )
    .await;
    assert_eq!(st, StatusCode::BAD_REQUEST, "{body}");
}

#[tokio::test]
async fn the_plans_and_the_name_check_are_the_shops_in_the_browsers_market() {
    let (r, _) = relay("holger").await;
    let (st, body, _) = call(&r, "GET", "/auth/signup/ladder", None, None).await;
    assert_eq!(st, StatusCode::OK);
    assert_eq!(body["market"], "SE", "Accept-Language sv-SE names Sweden");
    assert_eq!(body["plans"][1]["price_words"], "100.00 SEK a month");
    let (_, body, _) = call(&r, "GET", "/auth/signup/name?u=taken", None, None).await;
    assert_eq!(
        body,
        json!({"free": false, "reason": "username \"taken\" is taken; choose another"})
    );
    let (_, body, _) = call(&r, "GET", "/auth/signup/name?u=X", None, None).await;
    assert_eq!(body["free"], false);
}

#[tokio::test]
async fn a_made_account_is_handed_the_passkey_link_on_the_site_and_only_while_it_holds_none() {
    let (r, fake) = relay("holger").await;
    let (_, body, _) = call(
        &r,
        "GET",
        "/auth/signup/status?session=cs_test_abcdefghijkl",
        None,
        None,
    )
    .await;
    assert_eq!(body["state"], "pending");
    assert!(
        body.get("reason").is_none(),
        "the operator's reason never reaches the page"
    );
    *fake.created_user.lock().unwrap() = "x14".into();
    let (_, body, _) = call(
        &r,
        "GET",
        "/auth/signup/status?session=cs_test_abcdefghijkl",
        None,
        None,
    )
    .await;
    assert_eq!(body["state"], "created");
    assert_eq!(
        body["invite_url"],
        "/login?signup=cs_test_abcdefghijkl&user=x14"
    );
    *fake.created_user.lock().unwrap() = "done".into();
    let (_, body, _) = call(
        &r,
        "GET",
        "/auth/signup/status?session=cs_test_abcdefghijkl",
        None,
        None,
    )
    .await;
    assert_eq!(body["invite_url"], serde_json::Value::Null);
    let (st, _, _) = call(&r, "GET", "/auth/signup/status?session=../etc", None, None).await;
    assert_eq!(st, StatusCode::BAD_REQUEST);
    *fake.created_user.lock().unwrap() = "x14".into();
    let (st, body, _) = call(
        &r,
        "POST",
        "/auth/signup/sign-in-again",
        None,
        Some(json!({"session": "cs_test_abcdefghijkl", "next": "/"})),
    )
    .await;
    assert_eq!(st, StatusCode::OK, "{body}");
    assert_eq!(
        fake.heard
            .lock()
            .unwrap()
            .sign_in_again
            .as_ref()
            .unwrap()
            .welcome_url,
        format!("{ORIGIN}/welcome?session={{session}}&next=%2F")
    );
}

#[tokio::test]
async fn a_visitor_pays_once_for_a_private_instance_and_the_new_account_is_welcomed_on_the_site() {
    let (r, fake) = relay("holger").await;
    let (st, body, _) = call(&r, "POST", "/auth/private/start", None, Some(json!({"company": "acme", "account": "x14", "email": "ops@mock.invalid", "front_plan": "f", "main_plan": "m", "main_data_gib": 40}))).await;
    assert_eq!(st, StatusCode::OK, "{body}");
    assert_eq!(body["price_words"], "385.20 EUR");
    let h = fake.heard.lock().unwrap();
    let s = h.estate_start.as_ref().unwrap();
    assert!(s.new_account && s.actor_ticket.is_empty());
    assert_eq!(
        (s.account.as_str(), s.email.as_str()),
        ("x14", "ops@mock.invalid")
    );
    assert_eq!(
        s.welcome_url,
        format!(
            "{ORIGIN}/welcome?session={{session}}&next=%2Fsignup%3Fplan%3Dprivate%26company%3Dacme"
        )
    );
    assert_eq!(s.cancel_url, format!("{ORIGIN}/signup?plan=private"));
}

/// ★ **The product's own order rides from the page to the ONE box** (monetize v2.0 P3, the
/// parametric order): the values the page sends as `order` reach `EstateOrder.Start` and
/// `ChangePlan` as `EstateSizes.order` (JSON), unchanged; the ONE box checks them against the
/// product's form. A page that sends no order sends none; an order that is not a set of named
/// values, or is overlong, is refused on the site and never sent.
#[tokio::test]
async fn the_products_own_order_rides_to_the_one_box_as_it_came() {
    let (r, fake) = relay("holger").await;
    let (st, body, _) = call(
        &r,
        "POST",
        "/auth/private/start",
        Some("x14"),
        Some(json!({"company": "acme", "order": {"be": 3, "fe": 3, "graph": true}})),
    )
    .await;
    assert_eq!(st, StatusCode::OK, "{body}");
    let s = fake.heard.lock().unwrap().estate_start.clone().unwrap();
    let sent: serde_json::Value = serde_json::from_str(&s.sizes.unwrap().order).unwrap();
    assert_eq!(
        sent,
        json!({"be": 3, "fe": 3, "graph": true}),
        "the order as the page sent it"
    );
    let (st, _, _) = call(
        &r,
        "POST",
        "/auth/private/start",
        Some("x14"),
        Some(json!({"company": "acme2", "front_plan": "f"})),
    )
    .await;
    assert_eq!(st, StatusCode::OK);
    assert_eq!(
        fake.heard
            .lock()
            .unwrap()
            .estate_start
            .clone()
            .unwrap()
            .sizes
            .unwrap()
            .order,
        "",
        "no order: none sent"
    );
    let (st, _, _) = call(
        &r,
        "POST",
        "/auth/private/change",
        Some("x14"),
        Some(json!({"company": "acme", "order": {"be": 4}})),
    )
    .await;
    assert_eq!(st, StatusCode::OK);
    assert_eq!(
        fake.heard
            .lock()
            .unwrap()
            .change
            .clone()
            .unwrap()
            .sizes
            .unwrap()
            .order,
        r#"{"be":4}"#,
        "a change carries the order too"
    );
    for bad in [
        json!([1, 2]),
        json!("be=3"),
        json!({"blob": "x".repeat(monetize_site_buy::relay::ORDER_MAX)}),
    ] {
        fake.heard.lock().unwrap().estate_start = None;
        let (st, body, _) = call(
            &r,
            "POST",
            "/auth/private/start",
            Some("x14"),
            Some(json!({"company": "acme3", "order": bad})),
        )
        .await;
        assert_eq!(st, StatusCode::BAD_REQUEST, "{body}");
        assert!(
            fake.heard.lock().unwrap().estate_start.is_none(),
            "a refused order is never sent"
        );
    }
}

#[tokio::test]
async fn a_signed_in_buyer_orders_as_their_own_account_with_its_ticket_and_no_e_mail() {
    let (r, fake) = relay("holger").await;
    let (st, body, _) = call(&r, "POST", "/auth/private/start", Some("x14"), Some(json!({"company": "acme", "account": "somebody-else", "email": "other@mock.invalid", "front_plan": "f", "main_plan": "m", "main_data_gib": 40}))).await;
    assert_eq!(st, StatusCode::OK, "{body}");
    let s = fake.heard.lock().unwrap().estate_start.clone().unwrap();
    assert_eq!(
        s.account, "x14",
        "the order is the session's account, whatever the form says"
    );
    assert_eq!(s.actor_ticket, b"estate:x14:{}".to_vec());
    assert!(!s.new_account && s.welcome_url.is_empty());
    assert!(
        s.email.is_empty(),
        "the e-mail is asked once, never in a buy: a page's address is not sent ({:?})",
        s.email
    );
    // A credential that is no person, and a member, buy nothing.
    let (st, body, _) = call(
        &r,
        "POST",
        "/auth/private/start",
        Some("machine"),
        Some(json!({"company": "acme"})),
    )
    .await;
    assert_eq!(st, StatusCode::UNAUTHORIZED);
    assert_eq!(body["error"], "A private Holger is bought by your account at holger.mock.invalid, where you see and grow what you bought. Sign in, or Create your account at holger.mock.invalid first.");
    let (st, body, _) = call(
        &r,
        "POST",
        "/auth/private/start",
        Some("member:acme"),
        Some(json!({"company": "acme"})),
    )
    .await;
    assert_eq!(st, StatusCode::FORBIDDEN);
    assert_eq!(
        body["error"],
        "You are a member of acme. Members don’t buy: boss buys for acme."
    );
    let (st, _, _) = call(
        &r,
        "POST",
        "/auth/private/start",
        Some("x14"),
        Some(json!({"company": "taken"})),
    )
    .await;
    assert_eq!(st, StatusCode::CONFLICT);
}

#[tokio::test]
async fn an_instance_is_grown_and_followed_with_its_accounts_ticket() {
    let (r, fake) = relay("holger").await;
    let (st, body, _) = call(
        &r,
        "POST",
        "/auth/private/change",
        Some("x14"),
        Some(
            json!({"company": "acme", "front_plan": "f", "main_plan": "m2", "main_data_gib": 120}),
        ),
    )
    .await;
    assert_eq!(st, StatusCode::OK, "{body}");
    assert_eq!(body["reference"], "estate/acme/change-1");
    assert_eq!(
        fake.heard
            .lock()
            .unwrap()
            .change
            .as_ref()
            .unwrap()
            .actor_ticket,
        b"estate:x14:{}".to_vec()
    );
    let (_, body, _) = call(&r, "GET", "/auth/private/status?company=acme", None, None).await;
    assert_eq!(body["state"], "queued");
    assert!(
        fake.heard
            .lock()
            .unwrap()
            .status_ticket
            .as_ref()
            .unwrap()
            .is_empty(),
        "a visitor reads the state word only"
    );
    let (st, _, _) = call(
        &r,
        "GET",
        "/auth/private/status?company=acme",
        Some("down"),
        None,
    )
    .await;
    assert_eq!(
        st,
        StatusCode::SERVICE_UNAVAILABLE,
        "an outage is never a stranger's view"
    );
    let (_, body, _) = call(&r, "GET", "/auth/private/ladder", None, None).await;
    assert_eq!(body["steps"][0]["monthly_words"], "96.20 EUR a month");
}

#[tokio::test]
async fn the_vendors_way_back_from_a_private_order_lands_on_the_sites_watch() {
    let (r, _) = relay("holger").await;
    let (st, _, to) = call(&r, "GET", "/paid/estate/acme", None, None).await;
    assert_eq!(
        (st, to.as_deref()),
        (
            StatusCode::SEE_OTHER,
            Some("/signup?plan=private&company=acme")
        )
    );
    let (_, _, to) = call(&r, "GET", "/paid/estate/acme/change-3", None, None).await;
    assert_eq!(
        to.as_deref(),
        Some("/signup?plan=private&company=acme&change=1")
    );
}

#[tokio::test]
async fn the_accounts_grow_is_the_shops_window_and_the_ticket_covers_the_exact_target() {
    let (r, fake) = relay("holger").await;
    let (st, body, _) = call(
        &r,
        "GET",
        "/api/account/subscription/bundles",
        Some("x14"),
        None,
    )
    .await;
    assert_eq!(st, StatusCode::OK, "{body}");
    assert_eq!(
        body["offers"].as_array().unwrap().len(),
        1,
        "a row the box cannot serve is not shown"
    );
    assert_eq!(body["withheld"], 1);
    assert_eq!(body["offers"][0]["price_words"], "220.00 SEK");
    assert_eq!(body["market"], "SE");
    assert_eq!(
        fake.heard
            .lock()
            .unwrap()
            .bundles
            .as_ref()
            .unwrap()
            .actor_ticket,
        b"read:x14:{}".to_vec()
    );
    let (st, body, _) = call(
        &r,
        "POST",
        "/api/account/subscription/buy-bundle",
        Some("x14"),
        Some(json!({"bundle": "more10"})),
    )
    .await;
    assert_eq!(st, StatusCode::OK, "{body}");
    assert_eq!(
        body["url"],
        "https://checkout.mock.invalid/c/pay/cs_test_room"
    );
    assert_eq!(
        (
            body["before"]["disk_bytes"].as_u64(),
            body["after"]["disk_bytes"].as_u64()
        ),
        (Some(5), Some(15))
    );
    let p = fake.heard.lock().unwrap().purchase_start.clone().unwrap();
    assert_eq!((p.bundle.as_str(), p.tenant.as_str()), ("more10", "x14"));
    assert!(
        p.caps.is_empty(),
        "the caps go in the ticket, never beside the bundle"
    );
    assert_eq!(p.actor_ticket, b"order:x14:{\"disk_bytes\": 15}".to_vec());
    let (st, _, _) = call(
        &r,
        "POST",
        "/api/account/subscription/buy-bundle",
        Some("x14"),
        Some(json!({"bundle": "nope"})),
    )
    .await;
    assert_eq!(
        st,
        StatusCode::BAD_REQUEST,
        "a row monetize does not list is not ordered"
    );
    let (_, body, _) = call(
        &r,
        "GET",
        "/api/account/subscription/status?reference=p-1",
        Some("x14"),
        None,
    )
    .await;
    assert_eq!(
        (body["state"].as_str(), body["phase"].as_str()),
        (Some("paid"), Some("done"))
    );
    let (st, _, _) = call(&r, "GET", "/api/account/subscription/bundles", None, None).await;
    assert_eq!(st, StatusCode::UNAUTHORIZED, "a visitor grows nothing");
}

#[tokio::test]
async fn the_offer_names_the_sites_own_pages_never_the_shops() {
    let (r, _) = relay("holger").await;
    let (_, body, _) = call(&r, "GET", "/auth/buy/offer", Some("x14"), None).await;
    assert_eq!(
        body,
        json!({"signed_in": true, "account": "x14", "member": null, "account_url": "/signup?plan=account", "private_offered": true, "private_url": "/signup?plan=private"})
    );
    assert!(
        !body.to_string().contains("monetize."),
        "no link leaves the site"
    );
}

#[tokio::test]
async fn where_the_shop_mints_no_checkout_the_sites_fixed_link_is_used_with_the_typed_address() {
    let (r, _) = relay_with("gunnar", Some("https://buy.mock.invalid/b/x")).await;
    let (st, body, _) = call(
        &r,
        "POST",
        "/auth/signup/start",
        None,
        Some(json!({"username": "nosink", "email": "ops@mock.invalid"})),
    )
    .await;
    assert_eq!(st, StatusCode::OK, "{body}");
    assert_eq!(
        body["url"],
        "https://buy.mock.invalid/b/x?prefilled_email=ops%40mock.invalid"
    );
    let (r, _) = relay("holger").await;
    let (st, body, _) = call(
        &r,
        "POST",
        "/auth/signup/start",
        None,
        Some(json!({"username": "nosink", "email": "ops@mock.invalid"})),
    )
    .await;
    assert_eq!(
        (st, body["error"].as_str()),
        (
            StatusCode::NOT_IMPLEMENTED,
            Some("An account is not sold here right now.")
        )
    );
}

#[tokio::test]
async fn a_shop_that_does_not_answer_shows_the_last_offer_read_only_even_to_a_relay_made_again() {
    let (r, _) = relay("holger").await;
    let (st, _, _) = call(&r, "GET", "/auth/signup/ladder?market=fi", None, None).await;
    assert_eq!(st, StatusCode::OK);
    // A link to nothing: the shop does not answer.
    let shop = monetize_site_buy::ShopLink::connect_lazy(
        &monetize_site_buy::Door {
            url: "http://127.0.0.1:9".into(),
            ..Default::default()
        },
        BEARER,
        "holger",
    )
    .unwrap();
    let dead = std::sync::Arc::new(monetize_site_buy::Relay::new(
        common::Site {
            word: "Holger".into(),
            fixed: None,
        },
        shop,
    ));
    let (st, body, _) = call(&dead, "GET", "/auth/signup/ladder?market=fi", None, None).await;
    assert_eq!(st, StatusCode::SERVICE_UNAVAILABLE);
    assert_eq!(
        body["error"],
        "The shop is unavailable right now — try again in a few minutes."
    );
    assert_eq!(
        body["last_known"]["plans"][1]["price_words"],
        "100.00 SEK a month"
    );
}

/// ★ **Your purchases** (Gunnar's `api::subscription::purchases`, A14): the person's own
/// instances, each with its Grow and Manage pages on the site, asked with their `estate` ticket;
/// an account without room here gets the way to buy room here too.
#[tokio::test]
async fn your_purchases_list_the_persons_instances_with_their_grow_pages_on_the_site() {
    let (r, fake) = relay("holger").await;
    let (st, body, _) = call(&r, "GET", "/api/account/purchases", Some("x14"), None).await;
    assert_eq!(st, StatusCode::OK, "{body}");
    assert_eq!(body["estates"][0]["company"], "acme");
    assert_eq!(
        body["estates"][0]["grow_url"],
        "/signup?plan=grow&instance=acme"
    );
    assert_eq!(
        body["estates"][0]["renew_url"],
        "/signup?plan=private&renew=acme"
    );
    assert_eq!(
        body["storage_lines"][0]["words"],
        "Your Holger is acme.holger.mock.invalid"
    );
    assert_eq!(body["buy"]["url"], "/signup?plan=account");
    assert!(
        body["buy"]["words"]
            .as_str()
            .unwrap()
            .starts_with("Want space here on holger.mock.invalid too? Buy "),
        "{body}"
    );
    let asked = fake.heard.lock().unwrap().purchases.clone().unwrap();
    assert_eq!(
        (asked.account.as_str(), asked.actor_ticket.as_slice()),
        ("x14", b"estate:x14:{}".as_slice())
    );
    let (st, _, _) = call(&r, "GET", "/api/account/purchases", None, None).await;
    assert_eq!(st, StatusCode::UNAUTHORIZED, "a visitor has no purchases");
}