feat(workbench): add runtime GIS and sample integrations

This commit is contained in:
2026-09-22 10:44:31 +08:00
parent a3b4e75317
commit 7ab9b36a5e
62 changed files with 6685 additions and 51 deletions
+140
View File
@@ -0,0 +1,140 @@
from contextlib import asynccontextmanager
from copy import deepcopy
from datetime import datetime, timezone
from types import SimpleNamespace
from uuid import uuid4
import pytest
from app.domain.domain_errors import DomainError
from app.domain.schemas.task_alert import TaskAlertEvent
from app.services.task_alerts import TaskAlertService
NOW = datetime(2026, 9, 18, 2, 30, tzinfo=timezone.utc)
USER_ID = uuid4()
@pytest.fixture
def anyio_backend():
return "asyncio"
class Repository:
def __init__(self):
self.events = {}
self.alerts = {}
@asynccontextmanager
async def transaction(self):
yield self
async def lock_alert(self, _alert_id):
return None
async def get_event(self, producer_id, event_id):
return deepcopy(self.events.get((producer_id, event_id)))
async def get_alert(self, alert_id):
value = self.alerts.get(alert_id)
return (value["revision"], deepcopy(value["document"])) if value else None
async def save_event(self, event, resulting_state):
self.events[(event["producer_id"], event["event_id"])] = deepcopy(
event | {"resulting_state": resulting_state}
)
async def save_alert(self, state):
self.alerts[state["alert_id"]] = {
"revision": state["revision"],
"document": deepcopy({key: value for key, value in state.items() if key != "revision"}),
}
def command(
event_type="raised",
*,
event_id=None,
title="Low pressure",
producer_id=f"principal:{USER_ID}",
):
return TaskAlertEvent(
event_id=event_id or uuid4(),
producer_id=producer_id,
alert_id="schedule-1:2026-09-18T02:30:00Z",
event_type=event_type,
occurred_at=NOW,
condition_id=None,
source={
"task_type": "scheduled_task",
"task_id": "schedule-1",
"run_id": "occurrence-1",
},
title=title,
description="Scheduled task reported a failure.",
severity="warning",
)
@pytest.mark.anyio
async def test_alert_events_are_idempotent_and_transitions_are_monotonic():
repository = Repository()
service = TaskAlertService(
repository,
SimpleNamespace(project_role="member", user_id=USER_ID),
clock=lambda: NOW,
)
raised_command = command()
raised = await service.push(raised_command)
repeated = await service.push(raised_command)
assert raised.status == repeated.status == "active"
assert raised.revision == repeated.revision == 1
acknowledged = await service.push(command("acknowledged"))
resolved = await service.push(command("resolved"))
assert acknowledged.status == "acknowledged" and acknowledged.revision == 2
assert resolved.status == "resolved" and resolved.revision == 3
with pytest.raises(DomainError) as invalid:
await service.push(command("acknowledged"))
assert invalid.value.code == "INVALID_TRANSITION"
@pytest.mark.anyio
async def test_alert_event_reuse_and_fact_rewrites_are_rejected():
repository = Repository()
service = TaskAlertService(
repository,
SimpleNamespace(project_role="member", user_id=USER_ID),
clock=lambda: NOW,
)
event_id = uuid4()
await service.push(command(event_id=event_id))
with pytest.raises(DomainError) as reused:
await service.push(command(event_id=event_id, title="Changed"))
assert reused.value.code == "IDEMPOTENCY_CONFLICT"
with pytest.raises(DomainError) as rewritten:
await service.push(command("resolved", title="Changed"))
assert rewritten.value.code == "IDEMPOTENCY_CONFLICT"
@pytest.mark.anyio
async def test_internal_alert_producer_is_bound_without_user_membership():
repository = Repository()
service = TaskAlertService(
repository,
None,
clock=lambda: NOW,
internal_producer_id="scheduler:demo",
)
state = await service.push(command(producer_id="scheduler:demo"))
assert state.status == "active"
mismatched = command(producer_id="scheduler:demo")
mismatched.producer_id = "another-task"
with pytest.raises(DomainError) as denied:
await service.push(mismatched)
assert denied.value.code == "PERMISSION_DENIED"