minerva 0.2.0

Causal ordering for distributed systems
use super::{MonotonicTimeSource, SystemTimeSource};
use crate::kairos::{Clock, TimeSource};
use std::time::{SystemTime, UNIX_EPOCH};
use std::vec::Vec;

#[test]
fn monotonic_source_is_nondecreasing() {
    // Instant is monotonic; same-tick reads may be equal.
    let src = MonotonicTimeSource::new();
    let mut prev = src.now();
    for _ in 0..1000 {
        let next = src.now();
        assert!(
            next >= prev,
            "monotonic source stepped backward: {next} < {prev}"
        );
        prev = next;
    }
}

#[test]
fn system_source_reads_wall_clock() {
    // Bracket the source reading between independent wall-clock samples.
    let slack = 1_000_000_000u128;
    let before = SystemTime::now()
        .duration_since(UNIX_EPOCH)
        .expect("system clock is after the Unix epoch")
        .as_nanos();
    let reading = u128::from(SystemTimeSource::new().now());
    let after = SystemTime::now()
        .duration_since(UNIX_EPOCH)
        .expect("system clock is after the Unix epoch")
        .as_nanos();
    assert!(
        reading >= before.saturating_sub(slack),
        "reading {reading} precedes {before}"
    );
    assert!(
        reading <= after + slack,
        "reading {reading} follows {after}"
    );
}

#[test]
fn clock_driven_by_system_source_is_strictly_monotonic() {
    let clock =
        Clock::with_default_config(SystemTimeSource::new(), 1).expect("non-zero station_id");
    let mut stamps = Vec::with_capacity(1000);
    let mut prev = clock.now(0u16);
    stamps.push(prev);
    for _ in 1..1000 {
        let next = clock.now(0u16);
        assert!(
            next > prev,
            "HLC output must be strictly monotonic: {next:?} !> {prev:?}"
        );
        prev = next;
        stamps.push(next);
    }
    let len = stamps.len();
    stamps.sort_unstable();
    stamps.dedup();
    assert_eq!(len, stamps.len(), "stamps must be unique");
}

#[test]
fn clock_driven_by_monotonic_source_is_strictly_monotonic() {
    let clock =
        Clock::with_default_config(MonotonicTimeSource::new(), 9).expect("non-zero station_id");
    let mut prev = clock.now(0u16);
    for _ in 1..1000 {
        let next = clock.now(0u16);
        assert!(
            next > prev,
            "HLC output must be strictly monotonic: {next:?} !> {prev:?}"
        );
        prev = next;
    }
}