mirror of
https://github.com/rennf93/roboco.git
synced 2026-08-03 07:23:24 +02:00
79 lines
2.3 KiB
Python
79 lines
2.3 KiB
Python
"""NotificationDeliveryService._persist_and_deliver re-fire guard.
|
|||
|
|
|
||
|
|
Path 2 bypasses the DB dedup in NotificationService._create_notification, so
|
||
|
|
the same 60s Redis SET-NX guard gates it. Suppress (skip add/deliver) when the
|
||
|
|
guard says every recipient was just notified; pass through otherwise.
|
||
|
|
"""
|
||
|
|
|
||
|
|
from __future__ import annotations
|
||
|
|
|
||
|
|
from typing import Any
|
||
|
|
from unittest.mock import AsyncMock, MagicMock, patch
|
||
|
|
from uuid import uuid4
|
||
|
|
|
||
|
|
import pytest
|
||
|
|
from roboco.models import NotificationPriority, NotificationType
|
||
|
|
from roboco.services.notification_delivery import NotificationDeliveryService
|
||
|
|
|
||
|
|
|
||
|
|
def _notification(
|
||
|
|
ntype: NotificationType = NotificationType.TASK_ASSIGNMENT,
|
||
|
|
) -> MagicMock:
|
||
|
|
n = MagicMock()
|
||
|
|
n.id = uuid4()
|
||
|
|
n.type = ntype
|
||
|
|
n.from_agent = uuid4()
|
||
|
|
n.to_agents = [uuid4(), uuid4()]
|
||
|
|
n.related_task_id = uuid4()
|
||
|
|
n.priority = NotificationPriority.NORMAL
|
||
|
|
n.subject = "s"
|
||
|
|
n.body = "b"
|
||
|
|
n.requires_ack = True
|
||
|
|
return n
|
||
|
|
|
||
|
|
|
||
|
|
def _svc(session: MagicMock) -> Any:
|
||
|
|
"""Build the service with ``deliver`` stubbed via an Any-typed alias so the
|
||
|
|
reassignment stays type-clean (no method-assign suppression)."""
|
||
|
|
svc = NotificationDeliveryService(session)
|
||
|
|
cc: Any = svc
|
||
|
|
cc.deliver = AsyncMock()
|
||
|
|
return svc
|
||
|
|
|
||
|
|
|
||
|
|
@pytest.mark.asyncio
|
||
|
|
async def test_persist_and_deliver_suppresses_when_guard_true() -> None:
|
||
|
|
session = MagicMock()
|
||
|
|
session.add = MagicMock()
|
||
|
|
session.flush = AsyncMock()
|
||
|
|
svc = _svc(session)
|
||
|
|
|
||
|
|
with patch(
|
||
|
|
"roboco.services.notification_delivery.all_recipients_recently_notified",
|
||
|
|
AsyncMock(return_value=True),
|
||
|
|
):
|
||
|
|
await svc._persist_and_deliver(_notification())
|
||
|
|
|
||
|
|
session.add.assert_not_called()
|
||
|
|
session.flush.assert_not_awaited()
|
||
|
|
svc.deliver.assert_not_awaited()
|
||
|
|
|
||
|
|
|
||
|
|
@pytest.mark.asyncio
|
||
|
|
async def test_persist_and_deliver_passes_through_when_guard_false() -> None:
|
||
|
|
session = MagicMock()
|
||
|
|
session.add = MagicMock()
|
||
|
|
session.flush = AsyncMock()
|
||
|
|
svc = _svc(session)
|
||
|
|
|
||
|
|
notif = _notification()
|
||
|
|
with patch(
|
||
|
|
"roboco.services.notification_delivery.all_recipients_recently_notified",
|
||
|
|
AsyncMock(return_value=False),
|
||
|
|
):
|
||
|
|
await svc._persist_and_deliver(notif)
|
||
|
|
|
||
|
|
session.add.assert_called_once_with(notif)
|
||
|
|
session.flush.assert_awaited_once()
|
||
|
|
svc.deliver.assert_awaited_once()
|