83 lines
2.7 KiB
Python
83 lines
2.7 KiB
Python
from datetime import timedelta
|
|
|
|
import pytest
|
|
from django.utils import timezone
|
|
|
|
from apps.payments.models import Payment
|
|
from apps.payments.tasks import sweep_stale_payment_verifications
|
|
|
|
pytestmark = [pytest.mark.integration, pytest.mark.django_db]
|
|
|
|
|
|
def test_sweep_schedules_only_old_unresolved_payments_and_deduplicates_dispatch(
|
|
user_factory, event_factory, mocker, settings
|
|
):
|
|
settings.PAYMENT_VERIFICATION_GRACE_SECONDS = 1800
|
|
user = user_factory()
|
|
event = event_factory(price=25000)
|
|
old_payment = Payment.objects.create(
|
|
user=user,
|
|
event=event,
|
|
base_amount=25000,
|
|
amount=25000,
|
|
authority="AUTH-RECOVERY-OLD",
|
|
status=Payment.OrderStatusChoices.PENDING,
|
|
)
|
|
recent_payment = Payment.objects.create(
|
|
user=user,
|
|
event=event,
|
|
base_amount=25000,
|
|
amount=25000,
|
|
authority="AUTH-RECOVERY-NEW",
|
|
status=Payment.OrderStatusChoices.PENDING,
|
|
)
|
|
Payment.objects.filter(pk=old_payment.pk).update(
|
|
created_at=timezone.now() - timedelta(seconds=1801)
|
|
)
|
|
enqueue = mocker.patch("apps.payments.tasks.reconcile_payment.apply_async")
|
|
|
|
scheduled = sweep_stale_payment_verifications.run()
|
|
|
|
old_payment.refresh_from_db()
|
|
recent_payment.refresh_from_db()
|
|
assert scheduled == 1
|
|
enqueue.assert_called_once_with(args=(old_payment.pk,))
|
|
assert old_payment.verification_dispatch_expires_at is not None
|
|
assert old_payment.verification_dispatch_expires_at > timezone.now()
|
|
assert recent_payment.verification_next_attempt_at is None
|
|
|
|
assert sweep_stale_payment_verifications.run() == 0
|
|
enqueue.assert_called_once()
|
|
|
|
|
|
def test_sweep_does_not_restart_exhausted_or_terminal_attempts(
|
|
user_factory, event_factory, mocker, settings
|
|
):
|
|
settings.PAYMENT_VERIFICATION_GRACE_SECONDS = 60
|
|
settings.PAYMENT_VERIFICATION_MAX_ATTEMPTS = 3
|
|
user = user_factory()
|
|
event = event_factory(price=25000)
|
|
payments = [
|
|
Payment.objects.create(
|
|
user=user,
|
|
event=event,
|
|
base_amount=25000,
|
|
amount=25000,
|
|
authority=f"AUTH-RECOVERY-{status}-{index}",
|
|
status=status,
|
|
verification_attempts=3,
|
|
)
|
|
for index, status in enumerate(
|
|
[Payment.OrderStatusChoices.PENDING, Payment.OrderStatusChoices.FAILED]
|
|
)
|
|
]
|
|
Payment.objects.filter(pk__in=[payment.pk for payment in payments]).update(
|
|
created_at=timezone.now() - timedelta(minutes=5)
|
|
)
|
|
enqueue = mocker.patch("apps.payments.tasks.reconcile_payment.apply_async")
|
|
|
|
scheduled = sweep_stale_payment_verifications.run()
|
|
|
|
assert scheduled == 0
|
|
enqueue.assert_not_called()
|