Implement PostgreSQL production store path
All checks were successful
Build and Publish Container Image / build-and-push (push) Successful in 41s
All checks were successful
Build and Publish Container Image / build-and-push (push) Successful in 41s
Add the PostgreSQL backend, migration and stopped-write transfer tools, lease-aware deployment manifests, tenancy declarations, and shared conformance coverage. Persist grouping mutations in durable stores and separate process liveness from database readiness.
This commit is contained in:
parent
2063470ac8
commit
749461b97b
30 changed files with 2364 additions and 71 deletions
|
|
@ -1,6 +1,6 @@
|
|||
"""TEN-WP-0005-T02/T04: one lifecycle contract, both store backends.
|
||||
"""TEN-WP-0005-T02/T04: one lifecycle contract, every store backend.
|
||||
|
||||
Every test here is parametrised over the in-memory and SQLite stores so the
|
||||
Every test here is parametrised over the in-memory, SQLite, and PostgreSQL stores so the
|
||||
durable backend cannot silently diverge from the reference semantics -- the
|
||||
divergence that matters (CAS, idempotency, retirement guards) is exactly the
|
||||
kind a single-backend suite would miss.
|
||||
|
|
@ -9,6 +9,7 @@ kind a single-backend suite would miss.
|
|||
from datetime import UTC, datetime
|
||||
|
||||
import pytest
|
||||
from postgres_backend import clean_postgres_store
|
||||
|
||||
from tenant_engine.domain import (
|
||||
CapabilityRole,
|
||||
|
|
@ -30,11 +31,13 @@ from tenant_engine.store import (
|
|||
NOW = datetime(2026, 8, 10, 12, 0, tzinfo=UTC)
|
||||
|
||||
|
||||
@pytest.fixture(params=["memory", "sqlite"])
|
||||
@pytest.fixture(params=["memory", "sqlite", "postgres"])
|
||||
def store(request, tmp_path):
|
||||
if request.param == "memory":
|
||||
return InMemoryTenantStore()
|
||||
return SQLiteTenantStore(str(tmp_path / "tenant.db"))
|
||||
if request.param == "sqlite":
|
||||
return SQLiteTenantStore(str(tmp_path / "tenant.db"))
|
||||
return clean_postgres_store(tmp_path)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
|
|
@ -78,6 +81,22 @@ def test_update_persists_and_bumps_version(store, tenant) -> None:
|
|||
assert store.get_tenant("t-1").display_name == "Binky Ltd"
|
||||
|
||||
|
||||
def test_grouping_mutation_persists(store, tenant) -> None:
|
||||
updated, replayed = store.mutate_tenant(
|
||||
tenant_id="t-1",
|
||||
expected_version=1,
|
||||
mutate=lambda current: current.with_grouping("large", at=NOW),
|
||||
event_type="tenant_grouping_changed",
|
||||
evidence={"actor": "ops", "reason": "growth", "correlation_id": "corr-grouping"},
|
||||
idempotency_key="grouping-large",
|
||||
request_fingerprint="fp-grouping-large",
|
||||
)
|
||||
|
||||
assert replayed is False
|
||||
assert updated.grouping == "large"
|
||||
assert store.get_tenant("t-1").grouping == "large"
|
||||
|
||||
|
||||
def test_stale_version_is_rejected(store, tenant) -> None:
|
||||
_rename(store, key="k1", version=1)
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue