minerva 0.2.0

Causal ordering for distributed systems
use crate::metis::Dotted;

use super::super::{Seq, clock, position_of_run, prepend};

#[test]
fn test_backward_runs_at_the_origin_stay_contiguous() {
    // The B.2 scenario the sided anchor cures (S127). Under the old single-sided
    // left anchor, two concurrent prepend runs "ab" and "xy" built by repeated
    // insert-before at the document start merged as the INTERLEAVED "xayb". With
    // the Fugue Before side each run hangs in its own subtree, so the merged
    // reading is block-contiguous ("abxy" or "xyab"), never "xayb".
    let mut r1: Seq = Dotted::new();
    let mut r2: Seq = Dotted::new();
    let c1 = clock(1);
    let c2 = clock(2);

    // Replica 1 prepends "ab": type 'b' first (at the origin), then 'a' before it.
    let b1 = prepend(&mut r1, &c1, 1);
    let a1 = prepend(&mut r1, &c1, 1);
    assert_eq!(r1.store().order(), [a1, b1], "replica 1 reads 'ab'");

    // Replica 2 prepends "xy": type 'y' first, then 'x' before it.
    let y2 = prepend(&mut r2, &c2, 2);
    let x2 = prepend(&mut r2, &c2, 2);
    assert_eq!(r2.store().order(), [x2, y2], "replica 2 reads 'xy'");

    // Merge both ways; the reading is fold-order independent and block-contiguous.
    let merged = r1.merge(&r2);
    let order = merged.store().order();
    assert_eq!(merged.store().order(), r2.merge(&r1).store().order());

    let run1 = [a1, b1];
    let run2 = [x2, y2];
    let p1 = position_of_run(&order, &run1);
    let p2 = position_of_run(&order, &run2);
    assert!(
        p1.is_some(),
        "run 'ab' interleaved (the cured anomaly): {order:?}"
    );
    assert!(
        p2.is_some(),
        "run 'xy' interleaved (the cured anomaly): {order:?}"
    );
    assert_eq!(order.len(), 4);
    // The block order is decided by the runs' heads' ranks at the origin; assert
    // whichever the model gives. (The interleaved "xayb" is the cured anomaly.)
    let block = if p1.unwrap() < p2.unwrap() {
        [a1, b1, x2, y2]
    } else {
        [x2, y2, a1, b1]
    };
    assert_eq!(order, block);
}