This commit is contained in:
javad committed 2026-09-16 14:16:05 +03:30
1 parent 6b841dc5fa
commit 0ed677e5fc
10 files changed
+282 -16

No files matched your search

+127
View File
@@ -644,6 +644,133 @@ def test_worker_rechecks_provisional_delivery_until_definitive_result(category,c
assert job.delivery_status==NotificationJob.DeliveryStatus.DELIVERED
assert job.delivery_check_attempts==3 and job.delivery_next_check_at is None
@pytest.mark.django_db
def test_definitive_staff_created_delivery_failure_schedules_exactly_one_delayed_resend(category,customer,monkeypatch,settings):
from django.core.management import call_command
from apps.integrations.sms.base import SMSDeliveryResult,SMSResult
from apps.notifications.management.commands import process_notifications
settings.SMS_DEFINITIVE_DELIVERY_RETRY_AFTER_SECONDS=2700
staff=make_staff("delivery-retry-staff")
ticket=create_ticket(customer=customer,created_by=staff,unit=category.unit,category=category,subject="ارسال قطعی ناموفق",body="متن")
source=NotificationJob.objects.get(ticket=ticket,event_type="STAFF_TICKET_CREATED")
sent_at=timezone.now()
NotificationJob.objects.filter(pk=source.pk).update(
status=NotificationJob.Status.SENT,attempts=1,sent_at=sent_at,
provider_message_id="123456789",delivery_status=NotificationJob.DeliveryStatus.PENDING,
delivery_next_check_at=timezone.now()-timedelta(seconds=1),
)
class Provider:
def get_delivery_status(self,provider_id):
return SMSDeliveryResult("EXPIRED","7","مهلت دریافت پیامک منقضی شده است.",is_final=True)
def send_message(self,mobile,message):
return SMSResult(True,provider_id="223456789",provider_code="2")
monkeypatch.setattr(process_notifications,"get_sms_provider",lambda:Provider())
call_command("process_notifications",once=True,job_id=source.pk)
source.refresh_from_db()
retry=NotificationJob.objects.get(delivery_retry_source=source)
assert source.delivery_is_final is True
assert source.delivery_status==NotificationJob.DeliveryStatus.EXPIRED
assert retry.event_type=="STAFF_TICKET_CREATED" and retry.status==NotificationJob.Status.PENDING
assert retry.attempts==0 and retry.ticket_id==ticket.pk and retry.customer_id==customer.pk
assert sent_at+timedelta(seconds=2699) <= retry.next_attempt_at <= sent_at+timedelta(seconds=2701)
process_notifications._schedule_definitive_delivery_retry(source)
assert NotificationJob.objects.filter(delivery_retry_source=source).count()==1
NotificationJob.objects.filter(pk=retry.pk).update(next_attempt_at=timezone.now()-timedelta(seconds=1))
call_command("process_notifications",once=True,job_id=retry.pk)
retry.refresh_from_db()
assert retry.status==NotificationJob.Status.SENT and retry.attempts==1
assert retry.provider_message_id=="223456789"
retry.sent_at=timezone.now()-timedelta(hours=1)
retry.delivery_status=NotificationJob.DeliveryStatus.EXPIRED
retry.delivery_is_final=True
retry.save()
assert process_notifications._schedule_definitive_delivery_retry(retry) is None
assert NotificationJob.objects.filter(ticket=ticket,event_type="STAFF_TICKET_CREATED").count()==2
@pytest.mark.django_db
def test_provisional_or_unrelated_delivery_states_never_schedule_automatic_resend(category,customer,monkeypatch,settings):
from django.core.management import call_command
from apps.integrations.sms.base import SMSDeliveryResult
from apps.notifications.management.commands import process_notifications
settings.SMS_DELIVERY_MAX_CHECKS=1
staff=make_staff("provisional-retry-staff")
staff_ticket=create_ticket(customer=customer,created_by=staff,unit=category.unit,category=category,subject="دلیوری موقت",body="متن")
staff_job=NotificationJob.objects.get(ticket=staff_ticket,event_type="STAFF_TICKET_CREATED")
NotificationJob.objects.filter(pk=staff_job.pk).update(
status=NotificationJob.Status.SENT,sent_at=timezone.now()-timedelta(hours=1),
provider_message_id="123456789",delivery_status=NotificationJob.DeliveryStatus.PENDING,
delivery_next_check_at=timezone.now()-timedelta(seconds=1),
)
class Provider:
def get_delivery_status(self,provider_id):
return SMSDeliveryResult("UNDELIVERED","6","تحویل هنوز تأیید نشده است.",is_final=False)
monkeypatch.setattr(process_notifications,"get_sms_provider",lambda:Provider())
call_command("process_notifications",once=True,job_id=staff_job.pk)
staff_job.refresh_from_db()
assert staff_job.delivery_is_final is False
assert not NotificationJob.objects.filter(delivery_retry_source=staff_job).exists()
customer_ticket=create_ticket(customer=customer,category=category,subject="رویداد خارج از دامنه",body="متن")
unrelated=NotificationJob.objects.get(ticket=customer_ticket,event_type="CUSTOMER_TICKET_CREATED")
unrelated.status=NotificationJob.Status.SENT
unrelated.sent_at=timezone.now()-timedelta(hours=1)
unrelated.delivery_status=NotificationJob.DeliveryStatus.EXPIRED
unrelated.delivery_is_final=True
unrelated.save()
assert process_notifications._schedule_definitive_delivery_retry(unrelated) is None
@pytest.mark.django_db
def test_blocked_and_delivery_error_are_not_definitive_resend_candidates(category,customer):
from apps.notifications.management.commands import process_notifications
staff=make_staff("nonretryable-delivery-staff")
ticket=create_ticket(customer=customer,created_by=staff,unit=category.unit,category=category,subject="عدم ارسال مجدد خطا",body="متن")
source=NotificationJob.objects.get(ticket=ticket,event_type="STAFF_TICKET_CREATED")
source.status=NotificationJob.Status.SENT
source.sent_at=timezone.now()-timedelta(hours=1)
source.delivery_is_final=True
for status in (NotificationJob.DeliveryStatus.BLOCKED,NotificationJob.DeliveryStatus.ERROR):
source.delivery_status=status
source.save(update_fields=["status","sent_at","delivery_is_final","delivery_status"])
assert process_notifications._schedule_definitive_delivery_retry(source) is None
assert not NotificationJob.objects.filter(delivery_retry_source=source).exists()
@pytest.mark.django_db
def test_historical_expired_staff_ticket_delivery_is_queued_once_by_data_migration(category,customer,settings):
import importlib
from django.apps import apps as django_apps
settings.SMS_DEFINITIVE_DELIVERY_RETRY_AFTER_SECONDS=2700
settings.SMS_HISTORICAL_DELIVERY_RETRY_STAGGER_SECONDS=30
staff=make_staff("historical-delivery-staff")
ticket=create_ticket(customer=customer,created_by=staff,unit=category.unit,category=category,subject="خطای قدیمی دلیوری",body="متن")
source=NotificationJob.objects.get(ticket=ticket,event_type="STAFF_TICKET_CREATED")
NotificationJob.objects.filter(pk=source.pk).update(
status=NotificationJob.Status.SENT,sent_at=timezone.now()-timedelta(days=1),
provider_message_id="987654321",delivery_status=NotificationJob.DeliveryStatus.EXPIRED,
delivery_next_check_at=None,delivery_is_final=False,
)
migration=importlib.import_module("apps.notifications.migrations.0013_notificationjob_definitive_delivery_retry")
before=timezone.now()
migration.queue_historical_definitive_delivery_retries(django_apps,None)
retry=NotificationJob.objects.get(delivery_retry_source=source)
assert retry.status==NotificationJob.Status.PENDING
assert retry.next_attempt_at>=before+timedelta(seconds=29)
migration.queue_historical_definitive_delivery_retries(django_apps,None)
assert NotificationJob.objects.filter(delivery_retry_source=source).count()==1
@pytest.mark.django_db
def test_customer_ticket_created_sms_has_seven_day_magic_link(category,customer,settings,monkeypatch):
from datetime import timedelta