Files
alkblobs/tests/conformance/mem_column.rs
T
glm-5.3-flash f86e20a217 feat(tests): the conformance suite's mem column — the reference row set green (wave 2)
- rows.rs: the reference row set (INV-1…6 + two constructor-mode rows),
  factory-generic and engine-uniform, every row ADR-stamped and traced
  to the backlog: round-trips over the content matrix on both put
  paths, dedup (same/cross-path), stage hygiene (both paths, both
  injectable failure modes, kv-degenerate residue via sweep outcomes),
  sweep safety (full-protection-set happy shape, all three
  GcAbortCause abort shapes incl. the single-flight SweeperLock lease,
  the sweep-vs-pinned-put race), list correctness through exact sweep
  outcomes only, stat discipline, mem-only posture, and kv-only
  put-time rejection (threshold discovered by free probes; immediate/
  mid-stream rejections and at-threshold-lands legs)
- mem_column.rs: the column's factories — mem-only (reference host)
  and kv-only(mem) at a declared threshold — fresh isolated opens,
  no-op idempotent teardown; structural factory-contract tests cover
  isolation and teardown against a panicking row
- README: the reference row set recorded (INV-7's basis — what other
  columns mirror), the row-lifecycle convention, column plan and
  current state updated
- task suite-column-mem: status completed, notes and summary filled

Verification: cargo test --features mem (97 lib + 18 conformance +
4 git-interop), cargo test (default), cargo test --all-features,
clippy --all-features --all-targets -D warnings, fmt --check, and
cargo doc --no-deps — all green
2026-10-11 23:19:59 +00:00

241 lines
8.4 KiB
Rust

//! The **mem column** — the contract-reference column (ADR-011 §2):
//! the mem engine's column of the reference row set ([`crate::rows`]),
//! the first column bound to the real facade, and INV-7's basis —
//! every other engine's rows mirror this set.
//!
//! The factories (README §The factory contract): `open()` vends the
//! concrete [`alkblobs::Store`] facade over a fresh, isolated backing
//! store per call — the mem engine is `BTreeMap`-shaped and shares
//! nothing across instances, so isolation is by construction. Teardown
//! is a no-op (the mem engine holds no external state), which makes it
//! trivially idempotent and safe against abandoned instances — the
//! panicking-row path included, which the structural tests below
//! exercise. Mem never skips (README §SKIP posture — the SKIP
//! machinery stays unneeded until the SQL waves).
//!
//! The INV rows run against the reference `mem-only` factory (the kv
//! tier, no dispatch threshold in effect); the two constructor-mode
//! rows run against the mode factories they name — `mem-only`, and
//! `kv-only(mem)` at the column-declared threshold, which the kv-only
//! row discovers by probing.
#![allow(dead_code)]
use std::io::Cursor;
use std::sync::Arc;
use crate::factory::StoreFactory;
use crate::rows;
use alkblobs::{Error, Key, Store};
/// The reference factory: the mem-only mode (ADR-011 §4) — mem as the
/// sole engine, no dispatch threshold in effect. The column never
/// skips.
pub struct MemOnlyFactory;
impl StoreFactory for MemOnlyFactory {
fn name(&self) -> &'static str {
"mem-only"
}
async fn open(&self) -> Result<Store, Error> {
Ok(Store::mem_only())
}
async fn teardown(&self) -> Result<(), Error> {
Ok(())
}
}
/// The kv-only(mem) factory (ADR-011 §4; ADR-012 §6.2): no large
/// tier; the threshold is the put-time rejection point the kv-only
/// row discovers by probing.
pub struct KvOnlyMemFactory {
/// The rejection point this column's configuration declares. The
/// kv-only row discovers it behaviorally and requires it
/// materializable for its boundary legs.
pub threshold: u64,
}
impl StoreFactory for KvOnlyMemFactory {
fn name(&self) -> &'static str {
"kv-only(mem)"
}
async fn open(&self) -> Result<Store, Error> {
Ok(Store::kv_only_mem(self.threshold))
}
async fn teardown(&self) -> Result<(), Error> {
Ok(())
}
}
/// The column's declared kv-only threshold — small, so every leg of
/// the rejection row stays trivially materializable.
const KV_ONLY_THRESHOLD: u64 = 1024;
const MEM: MemOnlyFactory = MemOnlyFactory;
const KV_ONLY: KvOnlyMemFactory = KvOnlyMemFactory {
threshold: KV_ONLY_THRESHOLD,
};
// ------------------------------------------------------------------
// The reference row set, run against the mem column's factories.
// ------------------------------------------------------------------
#[tokio::test]
async fn inv1_round_trip_puts_and_gets_are_byte_identical() {
rows::round_trip_puts_and_gets_are_byte_identical(&MEM).await;
}
#[tokio::test]
async fn inv2_dedup_identical_content_is_one_pool_entry() {
rows::dedup_identical_content_is_one_pool_entry(&MEM).await;
}
#[tokio::test]
async fn inv3_stage_hygiene_zero_residue_on_failure_one_entry_on_success() {
rows::stage_hygiene_zero_residue_on_failure_exactly_one_entry_on_success(&MEM).await;
}
#[tokio::test]
async fn inv4_sweep_counts_are_exact_across_the_full_protection_set() {
rows::sweep_counts_are_exact_across_the_full_protection_set(&MEM).await;
}
#[tokio::test]
async fn inv4_sweep_without_liveness_sources_aborts_and_deletes_nothing() {
rows::sweep_without_liveness_sources_aborts_and_deletes_nothing(&MEM).await;
}
#[tokio::test]
async fn inv4_sweep_with_a_failed_protect_callback_aborts_and_deletes_nothing() {
rows::sweep_with_a_failed_protect_callback_aborts_and_deletes_nothing(&MEM).await;
}
#[tokio::test(flavor = "multi_thread", worker_threads = 4)]
async fn inv4_sweep_is_single_flight_the_contended_second_aborts_as_data() {
rows::sweep_is_single_flight_the_contended_second_aborts_as_data(&MEM).await;
}
#[tokio::test(flavor = "multi_thread", worker_threads = 4)]
async fn inv4_sweep_racing_a_pinned_put_never_deletes_the_protected_entry() {
rows::sweep_racing_a_pinned_put_never_deletes_the_protected_entry(&MEM).await;
}
#[tokio::test]
async fn inv5_list_correctness_is_observable_through_sweep_outcomes() {
rows::list_correctness_is_observable_through_sweep_outcomes(&MEM).await;
}
#[tokio::test]
async fn inv6_stat_reports_len_and_algorithm_without_fetching_content() {
rows::stat_reports_len_and_algorithm_without_fetching_content(&MEM).await;
}
#[tokio::test]
async fn constructor_mem_only_accepts_every_length_on_both_put_paths() {
rows::mem_only_mode_accepts_every_length_on_both_put_paths(&MEM).await;
}
#[tokio::test]
async fn constructor_kv_only_rejects_over_threshold_puts_at_put_time() {
rows::kv_only_mode_rejects_over_threshold_puts_at_put_time(&KV_ONLY).await;
}
// ------------------------------------------------------------------
// The factory contract's structural shapes (binding.rs' demonstrations
// carried to the real column factories): fresh isolated opens and
// idempotent teardown safe against a panicking row. These are not
// conformance rows — no backlog entry — they are the factory
// contract's own wiring-level assertions.
// ------------------------------------------------------------------
/// Every `open()` vends a fresh, isolated store: two stores live
/// concurrently without observable shared state, and a third open sees
/// neither island's entries.
#[tokio::test]
async fn factory_open_vends_fresh_isolated_stores() {
let a = MEM.open().await.expect("open vends a fresh store");
let b = MEM.open().await.expect("open vends another fresh store");
let content_a = b"island a's content".to_vec();
let content_b = b"island b's content".to_vec();
let (key_a, _) = a
.put(
Some(content_a.len() as u64),
Cursor::new(content_a.as_slice()),
)
.await
.expect("island a's put publishes");
let (key_b, _) = b
.put(None, Cursor::new(content_b.as_slice()))
.await
.expect("island b's put publishes");
assert!(a.has(&key_a.as_bytes()).await.unwrap());
assert!(
!a.has(&key_b.as_bytes()).await.unwrap(),
"island a sees nothing of island b"
);
assert!(b.has(&key_b.as_bytes()).await.unwrap());
assert!(
!b.has(&key_a.as_bytes()).await.unwrap(),
"island b sees nothing of island a"
);
let c = MEM.open().await.expect("a third open vends fresh");
assert!(
!c.has(&key_a.as_bytes()).await.unwrap(),
"a third open shares nothing with the first"
);
assert!(
!c.has(&key_b.as_bytes()).await.unwrap(),
"a third open shares nothing with the second"
);
}
/// A failing assertion panics the row before teardown runs — and
/// teardown must make sense over the abandoned instance anyway: it is
/// idempotent against the panicked row's path, and the next open vends
/// a fresh store with no residue (README §The factory contract).
#[tokio::test]
async fn factory_teardown_is_safe_against_a_panicking_row() {
let content = b"put before the assertion fails".to_vec();
let abandoned = Key::derive(&content, content.len() as u64);
let factory = Arc::new(MemOnlyFactory);
let task = {
let factory = Arc::clone(&factory);
tokio::spawn(async move {
let store = factory.open().await.expect("open vends the store");
let (_, pin) = store
.put(Some(content.len() as u64), Cursor::new(content.as_slice()))
.await
.expect("the put publishes");
drop(pin);
panic!("a failing assertion panics the row (the factory contract's early exit)");
})
};
assert!(
task.await.is_err(),
"the row's panic surfaced as its failure"
);
factory
.teardown()
.await
.expect("teardown makes sense over the abandoned instance");
factory.teardown().await.expect("teardown is idempotent");
let store = factory
.open()
.await
.expect("the next open still vends a store");
assert!(
!store.has(&abandoned.as_bytes()).await.unwrap(),
"no residue from the panicked row — isolation is factory-owned"
);
}