infrasynth-backend-kit/tests/test_webhooks/test_registry.py
2026-08-28 14:38:47 -05:00

130 lines
5.1 KiB
Python

from contextlib import contextmanager
from unittest import mock
import pytest
from django.db import transaction
from infrasynth.webhooks.models import (
OutboundDelivery,
OutboundEndpoint,
OutboundSubscription,
)
from infrasynth.webhooks.registry import EventDefinition, EventRegistry
pytestmark = pytest.mark.django_db
@contextmanager
def _emit_and_run_commit_hooks():
with transaction.atomic():
yield
connection = transaction.get_connection()
pending = list(connection.run_on_commit)
connection.run_on_commit = []
for entry in pending:
func = entry[1]
func()
@pytest.fixture(autouse=True)
def clean_registry():
EventRegistry._events.clear()
yield
EventRegistry._events.clear()
class TestRegister:
def test_register_creates_definition(self):
EventRegistry.register("helpdesk.ticket.created")
event = EventRegistry.get_registered_events()["helpdesk.ticket.created"]
assert isinstance(event, EventDefinition)
assert event.name == "helpdesk.ticket.created"
def test_register_with_metadata(self):
EventRegistry.register(
"helpdesk.ticket.resolved",
description="Ticket resolved",
example_payload={"ticket_id": 1},
schema={"type": "object"},
)
event = EventRegistry.get_registered_events()["helpdesk.ticket.resolved"]
assert event.description == "Ticket resolved"
assert event.example_payload == {"ticket_id": 1}
assert event.schema == {"type": "object"}
def test_get_registered_events_returns_copy(self):
EventRegistry.register("evt.a")
events = EventRegistry.get_registered_events()
events["evt.a"] = EventDefinition(name="mutated")
assert "evt.a" in EventRegistry.get_registered_events()
assert EventRegistry.get_registered_events()["evt.a"].name == "evt.a"
class TestEmit:
@pytest.fixture
def endpoint(self):
return OutboundEndpoint.objects.create(
name="Target",
url="https://example.com/hook",
secret="test-secret",
)
def test_emit_delivers_to_subscriber(self, endpoint):
subscription = OutboundSubscription.objects.create(endpoint=endpoint, event_name="helpdesk.ticket.created")
with mock.patch("infrasynth.webhooks.dispatch.requests.post") as post:
post.return_value.status_code = 200
post.return_value.text = "ok"
with _emit_and_run_commit_hooks():
EventRegistry.emit("helpdesk.ticket.created", {"ticket_id": 1})
delivery = OutboundDelivery.objects.get(subscription=subscription)
assert delivery.status == OutboundDelivery.Status.SUCCESS
assert delivery.payload == '{"ticket_id": 1}'
def test_emit_wildcard_subscription(self, endpoint):
subscription = OutboundSubscription.objects.create(endpoint=endpoint, event_name="*")
with mock.patch("infrasynth.webhooks.dispatch.requests.post") as post:
post.return_value.status_code = 200
post.return_value.text = "ok"
with _emit_and_run_commit_hooks():
EventRegistry.emit("any.event", {"x": 1})
assert OutboundDelivery.objects.filter(subscription=subscription).exists()
def test_emit_inactive_subscription_skipped(self, endpoint):
OutboundSubscription.objects.create(endpoint=endpoint, event_name="evt.x", is_active=False)
with mock.patch("infrasynth.webhooks.dispatch.requests.post") as post:
with _emit_and_run_commit_hooks():
EventRegistry.emit("evt.x", {})
post.assert_not_called()
assert not OutboundDelivery.objects.exists()
def test_emit_inactive_endpoint_skipped(self, endpoint):
OutboundSubscription.objects.create(endpoint=endpoint, event_name="evt.x", is_active=True)
endpoint.is_active = False
endpoint.save(update_fields=["is_active"])
with mock.patch("infrasynth.webhooks.dispatch.requests.post") as post:
with _emit_and_run_commit_hooks():
EventRegistry.emit("evt.x", {})
post.assert_not_called()
def test_emit_no_subscriptions_noop(self):
with mock.patch("infrasynth.webhooks.dispatch.requests.post") as post:
with _emit_and_run_commit_hooks():
EventRegistry.emit("unsubscribed.event", {})
post.assert_not_called()
def test_emit_sends_payload_template(self, endpoint):
subscription = OutboundSubscription.objects.create(
endpoint=endpoint,
event_name="evt.template",
payload_template='{"event": "{{ event.type }}"}',
)
with mock.patch("infrasynth.webhooks.dispatch.requests.post") as post:
post.return_value.status_code = 200
post.return_value.text = "ok"
with _emit_and_run_commit_hooks():
EventRegistry.emit("evt.template", {"type": "created"})
delivery = OutboundDelivery.objects.get(subscription=subscription)
assert delivery.payload == '{"event": "created"}'