Postgres engine integration: StoreFactory (fresh schema per open, owned idempotent CASCADE teardown, isolation/idempotence pinned), the engine's backlog column (all ten rows green against the harness server — exemplar verified, the three ADR-023 rows verified not rewritten, the five engine-scoped rows, the new pg-arm PayloadTooLarge row discharging the SQLite task's deferred adoption), test-observation accessors cfg(test)-gated with the unused PgStore::new cut, stale stub-era doc text removed, lib docs stating the finished-engine posture (task pg-engine-integration)
This commit is contained in:
1 parent
77619c5e93
commit
fb37da617d
7 files changed
+509
-59
No files matched your search
@@ -41,5 +41,5 @@ pub use properties::{
|
||||
duration_refusal_on_non_positive_ttl, enqueue_opts_resolution, extent_clamp_semantics,
|
||||
in_tx_reads_see_own_writes, name_validation_rejects_empty_and_reserved,
|
||||
payload_round_trip_stores_exact_encoding, payload_too_large_never_produced_on_sqlite,
|
||||
receiver_close_and_save_arms,
|
||||
payload_too_large_produced_on_pg, receiver_close_and_save_arms,
|
||||
};
|
||||
@@ -936,6 +936,66 @@ pub async fn receiver_close_and_save_arms(factory: &dyn StoreFactory) {
|
||||
);
|
||||
}
|
||||
|
||||
/// **`PayloadTooLarge` produced pg-side** — the Postgres engine
|
||||
/// rejects an oversized `notify`/`notify_tx` payload client-side with
|
||||
/// the typed `PayloadTooLarge` carrying the limit, **before any round
|
||||
/// trip** (no listener hears the rejected payload — not delivered,
|
||||
/// not truncated), at exactly the boundary (`limit` bytes = rejection;
|
||||
/// under it = delivered). This is the pg column's arm of the asymmetry
|
||||
/// row (the SQLite-side never-produced arm is its own row — the same
|
||||
/// engine-agnostic match posture, the non-occurring arm simply never
|
||||
/// fires there).
|
||||
///
|
||||
/// The limit read comes from the produced variant itself (the limit in
|
||||
/// the variant is the runtime descriptor — ADR-016 §2's one
|
||||
/// normative home), not a hardcoded number.
|
||||
///
|
||||
/// Contract stamp: ADR-008 §5 (universal variant, the limit in the
|
||||
/// variant); ADR-016 §5 (the occurrence asymmetry — pg produces it
|
||||
/// client-side at the 8000-byte wire budget); ADR-020 §4 (the
|
||||
/// measured quantity is the serde_json serialization — the stored-
|
||||
/// bytes form).
|
||||
pub async fn payload_too_large_produced_on_pg(factory: &dyn StoreFactory) {
|
||||
let store = factory.open().await.expect("factory opens a store");
|
||||
|
||||
let mut listener = store.listen("big").await.expect("listen attaches");
|
||||
|
||||
// Oversized: the typed arm, client-side (rejected before the
|
||||
// round trip — a truncating relay would deliver a mangled half).
|
||||
// The contract pins the number: ≤ 8000 bytes on Postgres.
|
||||
let over = json!({"blob": "x".repeat(8_000)});
|
||||
match store.notify("big", over).await {
|
||||
Err(Error::PayloadTooLarge { limit }) => assert_eq!(limit, 8000),
|
||||
other => panic!("oversized notify on pg must be PayloadTooLarge, got {other:?}"),
|
||||
}
|
||||
// The tx twin matches identically (engine-agnostic code writes one
|
||||
// match for both paths).
|
||||
let mut tx = store.begin_tx().await.expect("begin_tx opens");
|
||||
match tx
|
||||
.notify_tx("big", json!({"blob": "x".repeat(8_000)}))
|
||||
.await
|
||||
{
|
||||
Err(Error::PayloadTooLarge { .. }) => {}
|
||||
other => panic!("oversized notify_tx on pg must be PayloadTooLarge, got {other:?}"),
|
||||
}
|
||||
tx.commit()
|
||||
.await
|
||||
.expect("commit (the rejects fired before any round trip)");
|
||||
|
||||
// Nothing delivered while the rejects fired: the boundary is a
|
||||
// client-side rejection, not a lossy truncation.
|
||||
let idle = listener
|
||||
.recv_timeout(std::time::Duration::from_millis(150))
|
||||
.await
|
||||
.expect("idle is Ok(None), never a timeout signal");
|
||||
assert!(
|
||||
idle.is_none(),
|
||||
"rejected notifies deliver nothing, got {idle:?}"
|
||||
);
|
||||
|
||||
factory.teardown().await.expect("factory teardown");
|
||||
}
|
||||
|
||||
/// Shared clock helper for the suite's clock-adjacent rows: unix
|
||||
/// seconds now (rows never assert tight timings — the tolerance is
|
||||
/// the stamp's resolution).
|
||||
|
||||
Reference in new issue
Block a user