1
0
forked from erp-dev/erp
Files
erpnew/notifier/tests.py
2026-04-14 00:03:22 +08:00

192 lines
7.4 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
from unittest.mock import patch
from django.test import TestCase
from basic_info.models import Merchant, MerchantTypeEnum
from mission.models import MissionCategory
from notifier.models import NotificationEventKeyEnum, Notifier, NotifierChannelEnum, NotifierRoute
from notifier.services import (
dispatch_notification_event,
enqueue_notification_event,
render_notification_content,
send_notification_with_notifier,
)
class NotifierServiceTestCase(TestCase):
def setUp(self):
self.merchant = Merchant.objects.create(name="通知商户", type=MerchantTypeEnum.STORE)
self.general_category = MissionCategory.objects.create(merchant=self.merchant, name="通用")
self.after_sale_category = MissionCategory.objects.create(merchant=self.merchant, name="售后")
self.notifier = Notifier.objects.create(
merchant=self.merchant,
name="任务创建通知",
channel=NotifierChannelEnum.WECOM_WEBHOOK,
template_key="mission_created",
config={"key": "abc123", "msgtype": "markdown"},
)
self.global_route = NotifierRoute.objects.create(
merchant=self.merchant,
notifier=self.notifier,
event_key=NotificationEventKeyEnum.MISSION_CREATED,
)
def test_render_notification_content(self):
content = render_notification_content(
notifier=self.notifier,
payload={
"mission_id": 12,
"created_by_name": "张三",
"creator_name": "张三",
"category_name": "通用",
"is_urgent": False,
"participant_names_display": "李四、王五",
"description": "检查打印质量",
},
)
self.assertIn("任务已创建", content)
self.assertIn("任务ID12", content)
self.assertIn("创建人:张三", content)
@patch("notifier.backends.send_wecom_webhook_message")
def test_send_notification_with_notifier_uses_wecom_backend(self, mock_send):
mock_send.return_value.ok = True
mock_send.return_value.errcode = 0
mock_send.return_value.errmsg = "ok"
result = send_notification_with_notifier(
notifier=self.notifier,
payload={
"mission_id": 12,
"created_by_name": "张三",
"creator_name": "张三",
"category_name": "通用",
"is_urgent": True,
"participant_names_display": "",
"description": "检查打印质量",
},
)
self.assertEqual(result["status"], "sent")
self.assertEqual(result["channel"], NotifierChannelEnum.WECOM_WEBHOOK)
mock_send.assert_called_once()
@patch("notifier.services.send_notification_with_notifier")
def test_dispatch_notification_event_filters_by_route_event_and_enabled(self, mock_send):
mock_send.side_effect = lambda *, notifier, payload: {
"notifier_id": notifier.id,
"status": "sent",
}
replied_notifier = Notifier.objects.create(
merchant=self.merchant,
name="任务回应通知",
channel=NotifierChannelEnum.WECOM_WEBHOOK,
template_key="mission_replied",
config={"key": "def456"},
)
NotifierRoute.objects.create(
merchant=self.merchant,
notifier=replied_notifier,
event_key=NotificationEventKeyEnum.MISSION_REPLIED,
)
disabled_notifier = Notifier.objects.create(
merchant=self.merchant,
name="停用通知器",
channel=NotifierChannelEnum.WECOM_WEBHOOK,
template_key="mission_created",
is_enabled=False,
config={"key": "ghi789"},
)
NotifierRoute.objects.create(
merchant=self.merchant,
notifier=disabled_notifier,
event_key=NotificationEventKeyEnum.MISSION_CREATED,
)
results = dispatch_notification_event(
event_key=NotificationEventKeyEnum.MISSION_CREATED,
merchant_id=self.merchant.id,
payload={"mission_id": 99},
)
self.assertEqual(
results,
[
{
"notifier_id": self.notifier.id,
"status": "sent",
"event_key": NotificationEventKeyEnum.MISSION_CREATED,
"route_id": self.global_route.id,
"route_event_key": NotificationEventKeyEnum.MISSION_CREATED,
"route_mission_category_id": None,
}
],
)
self.assertEqual(mock_send.call_count, 1)
self.assertEqual(mock_send.call_args.kwargs["notifier"].id, self.notifier.id)
@patch("notifier.services.send_notification_with_notifier")
def test_dispatch_notification_event_prefers_category_specific_route(self, mock_send):
mock_send.side_effect = lambda *, notifier, payload: {
"notifier_id": notifier.id,
"status": "sent",
}
specific_route = NotifierRoute.objects.create(
merchant=self.merchant,
notifier=self.notifier,
event_key=NotificationEventKeyEnum.MISSION_CREATED,
mission_category=self.after_sale_category,
)
results = dispatch_notification_event(
event_key=NotificationEventKeyEnum.MISSION_CREATED,
merchant_id=self.merchant.id,
payload={"mission_id": 99, "category_id": self.after_sale_category.id},
)
self.assertEqual(mock_send.call_count, 1)
self.assertEqual(results[0]["route_id"], specific_route.id)
self.assertEqual(results[0]["route_mission_category_id"], self.after_sale_category.id)
@patch("notifier.services.send_notification_with_notifier")
def test_dispatch_notification_event_falls_back_to_global_route(self, mock_send):
mock_send.side_effect = lambda *, notifier, payload: {
"notifier_id": notifier.id,
"status": "sent",
}
results = dispatch_notification_event(
event_key=NotificationEventKeyEnum.MISSION_CREATED,
merchant_id=self.merchant.id,
payload={"mission_id": 99, "category_id": self.general_category.id},
)
self.assertEqual(mock_send.call_count, 1)
self.assertEqual(results[0]["route_id"], self.global_route.id)
self.assertIsNone(results[0]["route_mission_category_id"])
@patch("notifier.tasks.dispatch_notification_event_task.delay")
def test_enqueue_notification_event_returns_task_id(self, mock_delay):
mock_delay.return_value.id = "task-123"
task_id = enqueue_notification_event(
event_key=NotificationEventKeyEnum.MISSION_CREATED,
merchant_id=self.merchant.id,
payload={"mission_id": 1},
)
self.assertEqual(task_id, "task-123")
mock_delay.assert_called_once()
@patch("notifier.tasks.dispatch_notification_event_task.delay", side_effect=RuntimeError("broker down"))
def test_enqueue_notification_event_fails_open(self, mock_delay):
task_id = enqueue_notification_event(
event_key=NotificationEventKeyEnum.MISSION_CREATED,
merchant_id=self.merchant.id,
payload={"mission_id": 1},
)
self.assertIsNone(task_id)
mock_delay.assert_called_once()