148 lines
4.7 KiB
Python
148 lines
4.7 KiB
Python
from contextlib import contextmanager
|
|
from copy import deepcopy
|
|
from uuid import uuid4
|
|
|
|
import pytest
|
|
|
|
from samples.peripheral.auth import Identity
|
|
from samples.peripheral.config import SampleSettings
|
|
from samples.peripheral.schemas import TestDataRecord as DataRecordSchema
|
|
from samples.peripheral.schemas import WorkOrder
|
|
from samples.peripheral.store import PostgresStore
|
|
|
|
|
|
class FakeResult:
|
|
def __init__(self, *, row=None, rows=None):
|
|
self.row = row
|
|
self.rows = rows or []
|
|
|
|
def fetchone(self):
|
|
return self.row
|
|
|
|
def fetchall(self):
|
|
return self.rows
|
|
|
|
|
|
class ManagedProjectionConnection:
|
|
def __init__(self, table: str, document: dict):
|
|
self.table = table
|
|
self.document = document
|
|
|
|
def execute(self, statement, parameters):
|
|
normalized = " ".join(statement.split())
|
|
if "FROM peripheral_sample.scenarios" in normalized:
|
|
return FakeResult(row=None)
|
|
if f"FROM peripheral_sample.{self.table}" in normalized:
|
|
row = {"document": self.document}
|
|
return FakeResult(row=row, rows=[row])
|
|
raise AssertionError(f"unexpected query: {normalized}")
|
|
|
|
|
|
class ManagedProjectionStore(PostgresStore):
|
|
def __init__(self, table: str, document: dict):
|
|
super().__init__(SampleSettings())
|
|
self.fake_connection = ManagedProjectionConnection(table, document)
|
|
|
|
@contextmanager
|
|
def connection(self, *, readonly=False, timeseries=False):
|
|
assert readonly is True
|
|
assert timeseries is False
|
|
yield self.fake_connection
|
|
|
|
|
|
def work_order_document() -> dict:
|
|
now = "2026-09-18T00:00:00Z"
|
|
return {
|
|
"work_order_id": str(uuid4()),
|
|
"project_id": str(uuid4()),
|
|
"revision": 2,
|
|
"title": "恢复后的演示工单",
|
|
"summary": "当前行已恢复,但旧实现留下 tombstone 字段。",
|
|
"status": "open",
|
|
"priority": "normal",
|
|
"assignee": None,
|
|
"scheduled_at": None,
|
|
"origin": "synthetic",
|
|
"created_at": now,
|
|
"updated_at": now,
|
|
"created_by": str(uuid4()),
|
|
"updated_by": str(uuid4()),
|
|
"work_order_type": "general",
|
|
"location": None,
|
|
"scenario_code": None,
|
|
"deleted_at": now,
|
|
"deleted_by": str(uuid4()),
|
|
}
|
|
|
|
|
|
def test_active_work_order_projection_removes_only_tombstone_fields():
|
|
document = work_order_document()
|
|
stored_document = deepcopy(document)
|
|
store = ManagedProjectionStore("work_orders", stored_document)
|
|
who = Identity(document["project_id"], str(uuid4()), False)
|
|
|
|
result = store.get_work_order(who, document["work_order_id"])
|
|
|
|
assert "deleted_at" not in result
|
|
assert "deleted_by" not in result
|
|
assert stored_document == document
|
|
WorkOrder.model_validate(result)
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
("table", "id_column", "document", "model"),
|
|
[
|
|
("work_orders", "work_order_id", work_order_document(), WorkOrder),
|
|
(
|
|
"test_data_records",
|
|
"record_id",
|
|
{
|
|
"record_id": str(uuid4()),
|
|
"project_id": str(uuid4()),
|
|
"revision": 2,
|
|
"label": "恢复后的演示数据",
|
|
"point_id": "DEMO-P001",
|
|
"observed_at": "2026-09-18T00:00:00Z",
|
|
"value": 1.0,
|
|
"unit": "m",
|
|
"quality": "valid",
|
|
"notes": "",
|
|
"origin": "synthetic",
|
|
"created_at": "2026-09-18T00:00:00Z",
|
|
"updated_at": "2026-09-18T00:00:00Z",
|
|
"created_by": str(uuid4()),
|
|
"updated_by": str(uuid4()),
|
|
"deleted_at": "2026-09-18T00:00:00Z",
|
|
"deleted_by": str(uuid4()),
|
|
},
|
|
DataRecordSchema,
|
|
),
|
|
],
|
|
)
|
|
def test_active_managed_list_projection_removes_tombstone_fields(
|
|
table, id_column, document, model
|
|
):
|
|
store = ManagedProjectionStore(table, document)
|
|
who = Identity(document["project_id"], str(uuid4()), False)
|
|
|
|
page = store._list_managed(who, table, id_column, limit=10, cursor=None)
|
|
|
|
assert len(page["items"]) == 1
|
|
assert "deleted_at" not in page["items"][0]
|
|
assert "deleted_by" not in page["items"][0]
|
|
model.model_validate(page["items"][0])
|
|
|
|
|
|
def test_active_projection_does_not_hide_unrelated_fields():
|
|
document = {
|
|
"deleted_at": "2026-09-18T00:00:00Z",
|
|
"deleted_by": str(uuid4()),
|
|
"unexpected_field": "must remain visible to schema validation",
|
|
}
|
|
|
|
result = PostgresStore._active_managed_document(document)
|
|
|
|
assert result == {"unexpected_field": "must remain visible to schema validation"}
|
|
assert "deleted_at" in document
|
|
assert "deleted_by" in document
|