feat: strengthen module contracts and shared WebUI runtime

This commit is contained in:
2026-07-29 14:16:28 +02:00
parent 53e947935a
commit 68328f3d8e
57 changed files with 4358 additions and 371 deletions

View File

@@ -8,6 +8,8 @@ from unittest.mock import patch
from fastapi import APIRouter, Request
from fastapi.testclient import TestClient
from sqlalchemy import create_engine
from sqlalchemy.orm import Session
from govoplan_core.audit.logging import audit_event, audit_operation_context
from govoplan_core.core.events import (
@@ -17,6 +19,7 @@ from govoplan_core.core.events import (
EventTenantRef,
PlatformEvent,
current_event_trace,
emit_platform_event,
event_bus_context,
event_context,
normalize_trace_id,
@@ -31,13 +34,60 @@ from tests.db_isolation import temporary_database
def _configure_audit_runtime() -> None:
registry = build_platform_registry(("audit",))
registry = build_platform_registry(("access", "audit"))
context = ModuleContext(registry=registry, settings=object())
registry.configure_capability_context(context)
configure_runtime(context)
class CoreEventTests(unittest.TestCase):
def test_fallback_event_waits_for_outer_commit_after_savepoint(self) -> None:
engine = create_engine("sqlite:///:memory:")
seen: list[PlatformEvent] = []
bus = EventBus()
bus.subscribe("*", seen.append)
try:
with Session(engine) as session, event_bus_context(bus):
with session.begin():
with session.begin_nested():
emit_platform_event(
session,
PlatformEvent(type="nested.created", module_id="core"),
)
self.assertEqual([], seen)
self.assertEqual(
["nested.created"],
[event.type for event in seen],
)
finally:
engine.dispose()
def test_fallback_event_discards_only_rolled_back_savepoint(self) -> None:
engine = create_engine("sqlite:///:memory:")
seen: list[PlatformEvent] = []
bus = EventBus()
bus.subscribe("*", seen.append)
try:
with Session(engine) as session, event_bus_context(bus):
with session.begin():
emit_platform_event(
session,
PlatformEvent(type="outer.created", module_id="core"),
)
savepoint = session.begin_nested()
emit_platform_event(
session,
PlatformEvent(type="nested.created", module_id="core"),
)
savepoint.rollback()
self.assertEqual([], seen)
self.assertEqual(
["outer.created"],
[event.type for event in seen],
)
finally:
engine.dispose()
def test_event_bus_adds_trace_ids_and_propagates_causation_to_nested_events(self) -> None:
bus = EventBus()
seen: list[PlatformEvent] = []
@@ -267,6 +317,11 @@ class CoreEventTests(unittest.TestCase):
object_id="user-2",
details={"password": "secret", "field": "display_name"},
)
session.commit()
from govoplan_audit.backend.outbox import SqlAuditOutbox
SqlAuditOutbox().dispatch_pending(session)
session.commit()
action_events = [event for event in seen if event.type == "user.updated"]
self.assertEqual(1, len(action_events))
@@ -315,6 +370,11 @@ class CoreEventTests(unittest.TestCase):
object_type="demo",
object_id=action,
)
session.commit()
from govoplan_audit.backend.outbox import SqlAuditOutbox
SqlAuditOutbox().dispatch_pending(session)
session.commit()
by_type = {event.type: event.module_id for event in seen if event.type in cases}
self.assertEqual(cases, by_type)