use haematite::{BranchKind, BranchRefStore};
use super::{TestDirectory, TestResult, component, install};
use crate::{ComponentSchema, EntityId, StateError};
#[test]
fn install_write_archive_reinstall_is_fresh_and_aba_fenced() -> TestResult {
let directory = TestDirectory::new("archive-reinstall-aba")?;
let store = crate::ComponentStateStore::open(directory.path())?;
let id = component("aba");
let stale = install(&store, id)?;
let entity = stale.put(b"generation-zero")?;
let unrelated = stale.put(b"delete-me")?;
stale.commit()?;
stale.delete(unrelated)?;
stale.commit()?;
assert_eq!(
stale.enumerate()?,
vec![(entity, b"generation-zero".to_vec())]
);
let archive = store.archive_storage(id)?;
assert_eq!(archive.generation, 0);
assert_eq!(archive.snapshot_name, format!("archive/{id}/{:020}", 0_u64));
assert_eq!(
store.get_archived(id, 0, entity)?,
Some(b"generation-zero".to_vec())
);
store.declare_schema(id, ComponentSchema::lww())?;
let fresh = store.install_storage(id)?;
assert_eq!(fresh.incarnation(), 1);
assert!(fresh.enumerate()?.is_empty());
let fresh_root = fresh.current_root()?;
assert!(matches!(
stale.get(entity),
Err(StateError::StaleHandle {
component,
held: 0,
current: 1,
}) if component == id
));
assert!(matches!(
stale.put(b"must-not-land"),
Err(StateError::StaleHandle {
component,
held: 0,
current: 1,
}) if component == id
));
assert_eq!(fresh.current_root()?, fresh_root);
assert!(fresh.enumerate()?.is_empty());
let archives = store.list_archives(id)?;
assert_eq!(archives, vec![archive]);
assert_eq!(
store.get_archived(id, 0, entity)?,
Some(b"generation-zero".to_vec())
);
Ok(())
}
#[test]
fn healthy_boot_with_empty_runtime_registry_archives_and_heals_nothing() -> TestResult {
const ACTIVE_COMPONENTS: usize = 4;
let directory = TestDirectory::new("healthy-empty-runtime")?;
let mut roots = Vec::new();
{
let store = crate::ComponentStateStore::open(directory.path())?;
for index in 0..ACTIVE_COMPONENTS {
let id = component(&format!("healthy-{index}"));
let handle = install(&store, id)?;
let value = format!("value-{index}").into_bytes();
let entity = handle.put(&value)?;
roots.push((id, handle.commit()?, entity, value));
}
}
let rebooted = crate::ComponentStateStore::open(directory.path())?;
let report = rebooted.reconcile()?;
assert_eq!(report.healthy_active, ACTIVE_COMPONENTS);
assert!(report.actions.is_empty());
for (id, root, entity, value) in roots {
assert_eq!(rebooted.current_root(id)?, root);
assert_eq!(rebooted.component_handle(id)?.get(entity)?, Some(value));
assert!(rebooted.list_archives(id)?.is_empty());
}
Ok(())
}
#[test]
fn archive_abandons_mutated_and_clean_work_with_readable_roots_and_no_refs() -> TestResult {
let directory = TestDirectory::new("outstanding-work")?;
let store = crate::ComponentStateStore::open(directory.path())?;
let id = component("work-archive");
let namespace = install(&store, id)?;
let base = namespace.put(b"base")?;
namespace.commit()?;
let mutated = namespace.fork_work("mutated")?;
let speculative = mutated.put(b"speculative")?;
let clean = namespace.fork_work("clean")?;
let clean_root = clean.current_root()?;
let archive = store.archive_storage(id)?;
assert_eq!(archive.abandoned_work.len(), 2);
assert!(
archive
.abandoned_work
.iter()
.all(|work| work.kind == BranchKind::Work)
);
let mutated_record = archive
.abandoned_work
.iter()
.find(|work| work.branch.contains("6d757461746564"))
.expect("mutated Work evidence");
let clean_record = archive
.abandoned_work
.iter()
.find(|work| work.branch.contains("636c65616e"))
.expect("clean Work evidence");
assert_ne!(mutated_record.last_root, clean_root);
assert_eq!(clean_record.last_root, clean_root);
assert_eq!(
store.get_at_root(mutated_record.last_root, speculative)?,
Some(b"speculative".to_vec())
);
assert_eq!(
store.get_at_root(clean_record.last_root, base)?,
Some(b"base".to_vec())
);
let refs = BranchRefStore::open(directory.path().join("refs"))?;
let remaining: Vec<_> = refs.list().collect();
assert_eq!(remaining.len(), 1);
assert_eq!(remaining[0].name, "frame-state/meta");
assert_eq!(remaining[0].kind, BranchKind::Namespace);
let listed = store.list_archives(id)?;
assert_eq!(listed, vec![archive]);
Ok(())
}
#[test]
fn reconcile_refuses_foreign_namespace_without_meta_and_names_what_it_found() -> TestResult {
let directory = TestDirectory::new("foreign-namespace")?;
let id = component("foreign");
{
let store = crate::ComponentStateStore::open(directory.path())?;
store.lock_storage()?.create_namespace(id)?;
}
let rebooted = crate::ComponentStateStore::open(directory.path())?;
assert!(matches!(
rebooted.reconcile(),
Err(StateError::Reconcile(
crate::ReconcileInconsistency::BranchWithoutMeta {
branch,
kind: BranchKind::Namespace,
},
)) if branch == format!("component/{id}")
));
Ok(())
}
#[test]
fn namespace_name_and_kind_are_deterministic_and_creation_is_durable() -> TestResult {
let directory = TestDirectory::new("namespace-identity")?;
let id = component("identity");
{
let store = crate::ComponentStateStore::open(directory.path())?;
let _handle = install(&store, id)?;
}
let refs = BranchRefStore::open(directory.path().join("refs"))?;
let record = refs
.get(&format!("component/{id}"))
.expect("durable namespace ref");
assert_eq!(record.name, format!("component/{id}"));
assert_eq!(record.kind, BranchKind::Namespace);
assert_eq!(
record.resolved_namespace_lineage(),
Some(record.name.as_str())
);
Ok(())
}
#[test]
fn component_handle_has_only_own_namespace_and_checkout_is_read_only() -> TestResult {
let directory = TestDirectory::new("scoped-handle")?;
let store = crate::ComponentStateStore::open(directory.path())?;
let first_id = component("first");
let second_id = component("second");
let first = install(&store, first_id)?;
let second = install(&store, second_id)?;
let first_entity = first.put(b"first-only")?;
first.commit()?;
assert_eq!(second.get(first_entity)?, None);
let first_root = first.current_root()?;
let storage = store.lock_storage()?;
let view = haematite::checkout(&storage.nodes, first_root);
assert!(matches!(
view.put(b"foreign", b"write"),
Err(haematite::CheckoutError::ReadOnly)
));
Ok(())
}
#[test]
fn install_requires_schema_and_active_reinstall_is_typed() -> TestResult {
let directory = TestDirectory::new("install-refusals")?;
let store = crate::ComponentStateStore::open(directory.path())?;
let id = component("refusals");
assert!(matches!(
store.install_storage(id),
Err(StateError::SchemaNotDeclared { component }) if component == id
));
let _handle = install(&store, id)?;
assert!(matches!(
store.install_storage(id),
Err(StateError::AlreadyActive { component }) if component == id
));
assert!(matches!(
store.declare_schema(id, ComponentSchema::lww()),
Err(StateError::AlreadyActive { component }) if component == id
));
Ok(())
}
#[test]
fn change_detection_is_one_history_independent_root_comparison() -> TestResult {
let directory = TestDirectory::new("change-detection")?;
let store = crate::ComponentStateStore::open(directory.path())?;
let id = component("change-detection");
let handle = install(&store, id)?;
let before = store.current_root(id)?;
assert!(!store.has_changed(id, before)?);
handle.put(b"change")?;
assert!(!handle.has_changed(before)?);
let after = handle.commit()?;
assert_ne!(after, before);
assert!(store.has_changed(id, before)?);
assert!(!handle.has_changed(after)?);
Ok(())
}
#[test]
fn entity_ids_are_exact_fixed_width_blake3_digests() {
let id = EntityId::of(b"entity");
assert_eq!(id.as_bytes().len(), 32);
assert_eq!(*id.as_bytes(), haematite::Hash::of(b"entity").into_bytes());
}