pub mod common;
use nodedb_array::types::cell_value::value::CellValue;
use nodedb_lite::sync::array::inbound::outcome::InboundOutcome;
#[tokio::test(flavor = "multi_thread")]
async fn erase_tombstone_removes_cell() {
let harness = common::SyncHarness::new_in_memory().await;
harness.create_array("gdpr").await;
let schema_hlc = harness.schema_hlc("gdpr");
let rep = common::replica(1);
let put = common::put_op("gdpr", 2, 55.0, 100, schema_hlc, rep);
assert_eq!(harness.deliver(&put), InboundOutcome::Applied);
harness.flush("gdpr").await;
let before = harness.read_coord("gdpr", 2, i64::MAX).await;
assert_eq!(
before,
Some(CellValue::Float64(55.0)),
"cell must be visible before erase"
);
let erase = common::erase_op("gdpr", 2, 200, schema_hlc, rep);
let outcome = harness.deliver(&erase);
assert_eq!(outcome, InboundOutcome::Applied, "Erase op must be Applied");
harness.flush("gdpr").await;
let after = harness.read_coord("gdpr", 2, i64::MAX).await;
assert!(
after.is_none(),
"GDPR-erased cell must return None (got {after:?})"
);
}
#[tokio::test(flavor = "multi_thread")]
async fn erase_op_is_idempotent() {
let harness = common::SyncHarness::new_in_memory().await;
harness.create_array("gdpr_idem").await;
let schema_hlc = harness.schema_hlc("gdpr_idem");
let rep = common::replica(1);
let put = common::put_op("gdpr_idem", 3, 11.0, 50, schema_hlc, rep);
harness.deliver(&put);
harness.flush("gdpr_idem").await;
let erase = common::erase_op("gdpr_idem", 3, 100, schema_hlc, rep);
let first = harness.deliver(&erase);
assert_eq!(first, InboundOutcome::Applied);
let second = harness.deliver(&erase);
assert_eq!(
second,
InboundOutcome::Idempotent,
"re-delivering the same Erase must be Idempotent"
);
}
#[tokio::test(flavor = "multi_thread")]
async fn cross_replica_erase_removes_cell() {
let harness = common::SyncHarness::new_in_memory().await;
harness.create_array("xr_gdpr").await;
let schema_hlc = harness.schema_hlc("xr_gdpr");
let rep_a = common::replica(1);
let rep_b = common::replica(2);
let put = common::put_op("xr_gdpr", 9, 77.0, 100, schema_hlc, rep_a);
harness.deliver(&put);
harness.flush("xr_gdpr").await;
let before = harness.read_coord("xr_gdpr", 9, i64::MAX).await;
assert!(
before.is_some(),
"cell must exist before cross-replica erase"
);
let erase = common::erase_op("xr_gdpr", 9, 300, schema_hlc, rep_b);
let outcome = harness.deliver(&erase);
assert_eq!(outcome, InboundOutcome::Applied);
harness.flush("xr_gdpr").await;
let after = harness.read_coord("xr_gdpr", 9, i64::MAX).await;
assert!(
after.is_none(),
"cell must be gone after cross-replica Erase"
);
}
#[tokio::test(flavor = "multi_thread")]
async fn erase_nonexistent_coord_is_safe() {
let harness = common::SyncHarness::new_in_memory().await;
harness.create_array("no_cell").await;
let schema_hlc = harness.schema_hlc("no_cell");
let rep = common::replica(1);
let erase = common::erase_op("no_cell", 99, 500, schema_hlc, rep);
let _ = harness.deliver(&erase);
harness.flush("no_cell").await;
let val = harness.read_coord("no_cell", 99, i64::MAX).await;
assert!(val.is_none(), "non-existent coord must remain None");
}