iris-chat 0.1.53

Iris Chat command line client and shared encrypted chat core
Documentation
use super::*;
use std::time::Duration;

async fn endpoint() -> Arc<FipsEndpoint> {
    let mut config = fips_core::Config::new();
    config.node.control.enabled = false;
    config.node.discovery.lan.enabled = false;
    config.node.discovery.nostr.enabled = false;
    Arc::new(
        FipsEndpoint::builder()
            .config(config)
            .without_system_tun()
            .bind()
            .await
            .unwrap(),
    )
}

#[tokio::test]
async fn service_epoch_requires_same_endpoint_generation_and_survives_snapshots() {
    let first = endpoint().await;
    let second = endpoint().await;
    let mut history = None;
    let now = Instant::now();
    let record = |endpoint, history: &mut _, generation, instant| {
        Observation::capture(endpoint, None)
            .unwrap()
            .record(history, generation, instant)
    };
    let before = record(first.clone(), &mut history, 1, now);
    let after = record(first.clone(), &mut history, 1, now + Duration::from_secs(2));
    assert_eq!(before["epoch_id"], after["epoch_id"]);
    assert_ne!(before["sample_id"], after["sample_id"]);
    assert_eq!(after["elapsed_ms"], 2000);
    assert_eq!(after["services"].as_object().unwrap().len(), 2);
    assert!(after["pubsub_delivery"].is_null());
    assert!(!after.to_string().contains(first.npub()));
    let replaced = record(
        second.clone(),
        &mut history,
        1,
        now + Duration::from_secs(3),
    );
    assert_ne!(after["epoch_id"], replaced["epoch_id"]);
    let generation = record(
        second.clone(),
        &mut history,
        2,
        now + Duration::from_secs(4),
    );
    assert_ne!(replaced["epoch_id"], generation["epoch_id"]);
    first.shutdown().await.unwrap();
    second.shutdown().await.unwrap();
}

#[tokio::test]
async fn service_counter_overflow_and_clock_regression_discard_epoch() {
    let endpoint = endpoint().await;
    let mut history = None;
    let now = Instant::now();
    Observation::capture(endpoint.clone(), None)
        .unwrap()
        .record(&mut history, 1, now);
    let backwards = Observation::capture(endpoint.clone(), None)
        .unwrap()
        .record(&mut history, 1, now - Duration::from_millis(1));
    assert_eq!(backwards["status"], "invalid_counters");
    assert!(history.is_none());
    let mut overflow = Observation::capture(endpoint.clone(), None).unwrap();
    overflow
        .services
        .get_mut("hashtree")
        .unwrap()
        .discarded_outputs = u64::MAX;
    let overflow = overflow.record(&mut history, 1, now);
    assert_eq!(overflow["valid"], false);
    assert!(overflow.get("services").is_none());
    assert!(history.is_none());
    endpoint.shutdown().await.unwrap();
}

#[tokio::test]
async fn pubsub_availability_changes_epoch_and_never_fabricates_zero_delivery() {
    let endpoint = endpoint().await;
    let mut history = None;
    let before = Observation::capture(endpoint.clone(), None)
        .unwrap()
        .record(&mut history, 1, Instant::now());
    let pubsub = Arc::new(
        FipsPubsubClient::start(endpoint.clone(), Default::default())
            .await
            .unwrap(),
    );
    let available = Observation::capture(endpoint.clone(), Some(pubsub.clone()))
        .unwrap()
        .record(&mut history, 1, Instant::now());
    assert_ne!(before["epoch_id"], available["epoch_id"]);
    assert_eq!(available["pubsub_delivery"].as_object().unwrap().len(), 14);
    let repeated = Observation::capture(endpoint.clone(), Some(pubsub.clone()))
        .unwrap()
        .record(&mut history, 1, Instant::now());
    assert_eq!(available["epoch_id"], repeated["epoch_id"]);
    let absent = Observation::capture(endpoint.clone(), None)
        .unwrap()
        .record(&mut history, 1, Instant::now());
    assert_ne!(available["epoch_id"], absent["epoch_id"]);
    assert!(absent["pubsub_delivery"].is_null());
    pubsub.shutdown_shared().await;
    endpoint.shutdown().await.unwrap();
}