use std::collections::{BTreeMap, BTreeSet};
use crate::boot_history_harness::{
ReadCounts, ReadSource, StageReads, TestResult, during_stage, history_pair,
};
use haematite::tree::Hash;
use liminal::durability::bridge::block_on;
use super::registry::ConversationRegistry;
use super::registry_snapshot::{SNAPSHOT_KEY, write_registry_snapshot};
use super::routed_stream_codec::head_key;
const STREAM: &str = "liminal:participant-conversation-registry";
#[test]
fn registry_boot_history_reads_do_not_grow_with_duplicate_creation_history() -> TestResult<()> {
let payload = serde_json::to_vec(&serde_json::json!({
"schema_version": 1,
"conversation_id": 7,
}))?;
let pair = history_pair("registry-snapshot-v1", |store, range| {
let expected = range.end;
let start = range.start;
let payloads = range.map(|_| payload.clone()).collect();
let next = block_on(store.append_all(STREAM, payloads, start))??;
assert_eq!(next, expected);
let prior = block_on(store.get_routed(STREAM, SNAPSHOT_KEY))??;
write_registry_snapshot(
store,
prior.as_deref().map(Hash::of),
next,
&BTreeSet::from([7]),
)?;
Ok(())
})?;
let expected = StageReads::from([(
"registry".to_owned(),
BTreeMap::from([
(
ReadSource::RoutedValue {
route: STREAM.to_owned(),
key: SNAPSHOT_KEY.to_vec(),
},
ReadCounts {
rows: 1,
bytes: 64 + 8,
},
),
(
ReadSource::RoutedValue {
route: STREAM.to_owned(),
key: head_key(STREAM)?,
},
ReadCounts::default(),
),
(
ReadSource::StreamHead(STREAM.to_owned()),
ReadCounts { rows: 1, bytes: 8 },
),
]),
)]);
pair.assert_stage("registry", &expected, |store| {
let registry = ConversationRegistry::new(store);
let restored = during_stage("registry", || registry.restore())?;
assert_eq!(restored, vec![7]);
Ok(())
})?;
Ok(())
}
#[test]
fn registry_boot_history_fixture_uses_the_production_writer() {
let source = include_str!("tests_boot_history.rs");
assert!(!source.contains(concat!("LS", "RS")));
assert!(source.contains("write_registry_snapshot(\n"));
assert!(source.contains("key: head_key(STREAM)?"));
}
#[test]
fn harness_boot_history_rejects_a_full_registry_walk() -> TestResult<()> {
let payload = serde_json::to_vec(&serde_json::json!({
"schema_version": 1,
"conversation_id": 7,
}))?;
let bytes = u64::try_from(payload.len())?;
let pair = history_pair("registry-duplicate-v1", |store, range| {
let expected = range.end;
let start = range.start;
let payloads = range.map(|_| payload.clone()).collect();
assert_eq!(
block_on(store.append_all(STREAM, payloads, start))??,
expected
);
Ok(())
})?;
let expected = StageReads::from([(
"registry".to_owned(),
BTreeMap::from([(
ReadSource::Stream(STREAM.to_owned()),
ReadCounts {
rows: 1_000,
bytes: 1_000 * bytes,
},
)]),
)]);
let refusal = pair
.assert_stage("registry", &expected, |store| {
during_stage("registry", || -> TestResult<()> {
let mut sequence = 0_u64;
loop {
let rows = block_on(store.read_from(STREAM, sequence, 64))??;
if rows.is_empty() {
break;
}
for row in rows {
assert_eq!(row.sequence, sequence);
assert_eq!(row.payload, payload);
sequence = sequence.checked_add(1).ok_or("control sequence overflow")?;
}
}
assert!(crate::boot_history_harness::HISTORY_ROWS.contains(&sequence));
Ok(())
})
})
.err()
.ok_or("boot history harness accepted a full registry walk")?
.to_string();
assert!(refusal.starts_with("boot stage registry: expected "));
assert!(refusal.contains(&format!("rows: 1000, bytes: {}", 1_000 * bytes)));
assert!(refusal.contains(&format!("rows: 100000, bytes: {}", 100_000 * bytes)));
Ok(())
}