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/tests/bench_travel.rs

//! **The mock's time travel** (g-nonpay proof, 2026-09-29): the owner's ruling
//! is proven on a gunnar mock whose clock TRAVELS — lapse, day 0, 23, 29, the
//! deletion at 30 — and the whole estate cannot jump thirty days (every
//! credential the appliance checks is five minutes wide, and the front steps
//! its clock hourly at most). So monetize's DECISION clock alone travels: it is
//! the wall clock plus an offset the bench serves (`bench_travel_url`), while
//! every fact is still SIGNED on the wall clock and every credential stays true.
//!
//! Fenced: the URL must be plain http on loopback or the offline mock's host
//! alias `10.0.2.100` — a deployment that named anything else is refused at
//! start, by name.

use std::io::{Read, Write};
use std::net::TcpListener;
use std::sync::atomic::{AtomicI64, Ordering};
use std::sync::Arc;
use std::time::Duration;

use monetize_server::bench::{travel_clock, travel_refusal};

const DAY: i64 = 24 * 60 * 60 * 1000;

fn serve(offset: Arc<AtomicI64>) -> String {
    let l = TcpListener::bind("127.0.0.1:0").unwrap();
    let url = format!("http://{}/", l.local_addr().unwrap());
    std::thread::spawn(move || {
        for s in l.incoming() {
            let mut s = s.unwrap();
            let mut b = [0u8; 512];
            let _ = s.read(&mut b);
            let body = format!("{{\"offset_ms\": {}}}", offset.load(Ordering::SeqCst));
            let _ = s.write_all(format!("HTTP/1.0 200 OK\r\nContent-Length: {}\r\n\r\n{body}", body.len()).as_bytes());
        }
    });
    url
}

fn wall() -> i64 {
    std::time::SystemTime::now().duration_since(std::time::UNIX_EPOCH).unwrap().as_millis() as i64
}

#[test]
fn the_decision_clock_follows_the_bench_offset_and_only_a_local_url_is_taken() {
    let offset = Arc::new(AtomicI64::new(0));
    let url = serve(offset.clone());
    let (clock, travel) = travel_clock(&url, Duration::from_millis(50)).expect("a loopback URL is taken");
    assert!((clock() as i64 - wall()).abs() < 5_000, "no offset: the wall clock");
    offset.store(30 * DAY, Ordering::SeqCst);
    let deadline = std::time::Instant::now() + Duration::from_secs(10);
    while travel.offset_ms() != 30 * DAY && std::time::Instant::now() < deadline {
        std::thread::sleep(Duration::from_millis(20));
    }
    assert_eq!(travel.offset_ms(), 30 * DAY, "the offset was taken");
    assert!((clock() as i64 - wall() - 30 * DAY).abs() < 5_000, "the decision clock is thirty days on");

    for bad in ["https://10.0.2.100:1/", "http://example.com/", "http://94.237.40.9:80/", "ftp://127.0.0.1/"] {
        assert!(travel_refusal(bad).is_some(), "{bad} must be refused");
    }
    for ok in ["http://127.0.0.1:18999/", "http://10.0.2.100:18999/"] {
        assert!(travel_refusal(ok).is_none(), "{ok}");
    }
    assert!(travel_clock("http://example.com/", Duration::from_secs(1)).is_err());
    // And a monetize.toml that names one is refused at load, by name.
    let e = monetize_server::config::Config::from_toml("bench_travel_url = \"http://example.com/\"\n").unwrap_err().to_string();
    assert!(e.contains("[bench-travel-not-local]"), "{e}");
    assert!(monetize_server::config::Config::from_toml("bench_travel_url = \"http://10.0.2.100:18999/\"\n").is_ok());
}