#[path = "common/harness.rs"]
mod harness;
use std::time::Duration;
use harness::TestHarness;
use macrame::error::DbError;
use macrame::graph::EdgeAssertion;
use macrame::{BranchId, ConceptUpsert, Database};
const EPOCH: &str = "1970-01-01T00:00:00.000000Z";
const OPEN: &str = "9999-12-31T23:59:59.999999Z";
const HOUR: Duration = Duration::from_secs(3_600);
fn id(name: &str) -> BranchId {
BranchId::new(name).expect("valid branch name")
}
fn edge(source: &str, target: &str) -> EdgeAssertion {
EdgeAssertion::new(source, target, "LINKS")
.valid_from(EPOCH)
.valid_to(OPEN)
}
async fn seeded(h: &TestHarness) -> Database {
let db = h.db_with_fake_clock().await;
db.write_concepts(
["a", "b", "c"]
.iter()
.map(|n| ConceptUpsert::new(*n, "n").valid_from(EPOCH))
.collect(),
)
.await
.unwrap();
db
}
#[tokio::test]
async fn an_archive_after_a_refused_overlap_still_commits() {
let h = TestHarness::new();
let db = seeded(&h).await;
db.assert_edge(
EdgeAssertion::new("a", "b", "LINKS")
.valid_from(EPOCH)
.valid_to("1970-01-01T01:00:00.000000Z"),
)
.await
.unwrap();
let overlapping = EdgeAssertion::new("a", "b", "LINKS")
.valid_from("1970-01-01T00:30:00.000000Z")
.valid_to("1970-01-01T02:00:00.000000Z");
assert!(
matches!(
db.assert_edge(overlapping).await,
Err(DbError::OverlappingInterval { .. })
),
"the fixture must actually reach the guard's overlap arm"
);
h.advance(HOUR);
db.archive("1970-01-01T00:15:00.000000Z")
.await
.expect("a live statement on the connection is what refuses a commit");
db.assert_edge(edge("a", "c")).await.unwrap();
}
#[tokio::test]
async fn a_write_naming_a_forgotten_lineage_is_refused_by_name() {
let h = TestHarness::new();
let db = seeded(&h).await;
db.fork(id("alt"), BranchId::main()).await.unwrap();
db.assert_edge(edge("a", "b").on_branch(id("alt")))
.await
.unwrap();
db.archive_branch(id("alt")).await.unwrap();
match db.assert_edge(edge("a", "c").on_branch(id("alt"))).await {
Err(DbError::UnknownBranch(name)) => assert_eq!(name, "alt"),
other => panic!("expected UnknownBranch(\"alt\"), got {other:?}"),
}
}
#[tokio::test]
async fn a_write_on_a_lineage_forked_this_turn_is_accepted() {
let h = TestHarness::new();
let db = seeded(&h).await;
db.assert_edge(edge("a", "b")).await.unwrap();
db.fork(id("alt"), BranchId::main()).await.unwrap();
db.assert_edge(edge("a", "c").on_branch(id("alt")))
.await
.expect("the lineage exists, and the actor wrote it itself one turn ago");
}
#[tokio::test]
async fn the_guard_is_recompiled_when_the_fork_changes_its_shape() {
let h = TestHarness::new();
let db = seeded(&h).await;
db.assert_edge(edge("a", "b")).await.unwrap();
db.fork(id("alt"), BranchId::main()).await.unwrap();
db.assert_edge(
EdgeAssertion::new("a", "c", "LINKS")
.valid_from(EPOCH)
.valid_to("1970-01-01T01:00:00.000000Z")
.on_branch(id("alt")),
)
.await
.unwrap();
db.assert_edge(
EdgeAssertion::new("a", "c", "LINKS")
.valid_from("1970-01-01T00:30:00.000000Z")
.valid_to("1970-01-01T02:00:00.000000Z"),
)
.await
.expect("the shape moved under the cached guard, which must be recompiled");
}