use nodedb::bridge::envelope::Status;
use nodedb_crdt::policy::{CollectionPolicy, ConflictPolicy};
use nodedb_physical::physical_plan::{CrdtOp, DocumentOp, EnforcementOptions, PhysicalPlan};
use crate::helpers::{TestCtx, make_ctx};
const COLLECTION: &str = "orders";
fn escalate_unique_policy_json() -> String {
let mut policy = CollectionPolicy::ephemeral();
policy.unique = ConflictPolicy::EscalateToDlq;
sonic_rs::to_string(&policy).expect("serialize policy")
}
fn register(ctx: &mut TestCtx, collection: &str, conflict_policy: Option<String>) {
let resp = crate::helpers::send_raw(
&mut ctx.core,
&mut ctx.tx,
&mut ctx.rx,
PhysicalPlan::Document(DocumentOp::Register {
collection: collection.into(),
indexes: Vec::new(),
crdt_enabled: false,
storage_mode: Default::default(),
enforcement: Box::new(EnforcementOptions::default()),
bitemporal: false,
conflict_policy,
}),
);
assert_eq!(resp.status, Status::Ok, "register document collection");
}
fn get_policy(ctx: &mut TestCtx, collection: &str) -> CollectionPolicy {
let payload = crate::helpers::send_ok(
&mut ctx.core,
&mut ctx.tx,
&mut ctx.rx,
PhysicalPlan::Crdt(CrdtOp::GetPolicy {
collection: collection.into(),
}),
);
sonic_rs::from_slice(&payload).expect("decode CollectionPolicy JSON")
}
#[test]
fn register_without_conflict_policy_uses_ephemeral_default() {
let mut ctx = make_ctx();
register(&mut ctx, COLLECTION, None);
let policy = get_policy(&mut ctx, COLLECTION);
assert!(
matches!(policy.unique, ConflictPolicy::RenameSuffix),
"unconfigured collection must resolve to the ephemeral RenameSuffix default"
);
}
#[test]
fn register_with_conflict_policy_rehydrates_registry() {
let mut ctx = make_ctx();
register(&mut ctx, COLLECTION, Some(escalate_unique_policy_json()));
let policy = get_policy(&mut ctx, COLLECTION);
assert!(
matches!(policy.unique, ConflictPolicy::EscalateToDlq),
"persisted ESCALATE_TO_DLQ policy must be visible immediately after Register"
);
}
#[test]
fn conflict_policy_survives_simulated_restart() {
let policy_json = escalate_unique_policy_json();
{
let mut ctx = make_ctx();
register(&mut ctx, COLLECTION, Some(policy_json.clone()));
let policy = get_policy(&mut ctx, COLLECTION);
assert!(matches!(policy.unique, ConflictPolicy::EscalateToDlq));
}
let mut ctx = make_ctx();
register(&mut ctx, COLLECTION, Some(policy_json));
let policy = get_policy(&mut ctx, COLLECTION);
assert!(
matches!(policy.unique, ConflictPolicy::EscalateToDlq),
"conflict policy must survive a restart via catalog-sourced Register \
rehydration, not silently revert to the ephemeral RenameSuffix default"
);
}