Add order expiry tests

This commit is contained in:
Reckless_Satoshi 2023-11-22 13:16:25 +00:00
parent 14340fd64b
commit 62ef86f1b4
No known key found for this signature in database
GPG Key ID: 9C4585B561315571
5 changed files with 180 additions and 53 deletions

View File

@ -8,68 +8,65 @@ from api.models import Order
class Command(BaseCommand):
help = "Follows all active hold invoices"
help = "Follows all active orders and make them expire if needed."
# def add_arguments(self, parser):
# parser.add_argument('debug', nargs='+', type=boolean)
do_nothing = [
Order.Status.UCA,
Order.Status.EXP,
Order.Status.DIS,
Order.Status.CCA,
Order.Status.PAY,
Order.Status.SUC,
Order.Status.FAI,
Order.Status.MLD,
Order.Status.TLD,
Order.Status.WFR,
]
def clean_orders(self, *args, **options):
"""Continuously checks order expiration times for 1 hour. If order
def clean_orders(self):
"""Continuously checks order expiration times. If order
has expires, it calls the logics module for expiration handling."""
do_nothing = [
Order.Status.UCA,
Order.Status.EXP,
Order.Status.DIS,
Order.Status.CCA,
Order.Status.PAY,
Order.Status.SUC,
Order.Status.FAI,
Order.Status.MLD,
Order.Status.TLD,
Order.Status.WFR,
]
queryset = Order.objects.exclude(status__in=self.do_nothing)
queryset = queryset.filter(
expires_at__lt=timezone.now()
) # expires at lower than now
while True:
time.sleep(5)
debug = {}
debug["num_expired_orders"] = len(queryset)
debug["expired_orders"] = []
debug["failed_order_expiry"] = []
debug["reason_failure"] = []
queryset = Order.objects.exclude(status__in=do_nothing)
queryset = queryset.filter(
expires_at__lt=timezone.now()
) # expires at lower than now
for idx, order in enumerate(queryset):
context = str(order) + " was " + Order.Status(order.status).label
try:
if Logics.order_expires(order): # Order send to expire here
debug["expired_orders"].append({idx: context})
debug = {}
debug["num_expired_orders"] = len(queryset)
debug["expired_orders"] = []
debug["failed_order_expiry"] = []
debug["reason_failure"] = []
# It should not happen, but if it cannot locate the hold invoice
# it probably was cancelled by another thread, make it expire anyway.
except Exception as e:
debug["failed_order_expiry"].append({idx: context})
debug["reason_failure"].append({idx: str(e)})
for idx, order in enumerate(queryset):
context = str(order) + " was " + Order.Status(order.status).label
try:
if Logics.order_expires(order): # Order send to expire here
debug["expired_orders"].append({idx: context})
if "unable to locate invoice" in str(e):
self.stdout.write(str(e))
order.update_status(Order.Status.EXP)
debug["expired_orders"].append({idx: context})
# It should not happen, but if it cannot locate the hold invoice
# it probably was cancelled by another thread, make it expire anyway.
except Exception as e:
debug["failed_order_expiry"].append({idx: context})
debug["reason_failure"].append({idx: str(e)})
if "unable to locate invoice" in str(e):
self.stdout.write(str(e))
order.update_status(Order.Status.EXP)
debug["expired_orders"].append({idx: context})
if debug["num_expired_orders"] > 0:
self.stdout.write(str(timezone.now()))
self.stdout.write(str(debug))
if debug["num_expired_orders"] > 0:
self.stdout.write(str(timezone.now()))
self.stdout.write(str(debug))
def handle(self, *args, **options):
"""Never mind database locked error, keep going, print them out.
Not an issue with PostgresQL"""
try:
self.clean_orders()
while True:
self.clean_orders()
time.sleep(5)
except Exception as e:
if "database is locked" in str(e):
self.stdout.write("database is locked")

View File

@ -7,19 +7,20 @@ from decouple import config
from django.contrib.auth.models import User
from django.urls import reverse
from api.management.commands.clean_orders import Command as CleanOrders
from api.management.commands.follow_invoices import Command as FollowInvoices
from api.models import Currency, Order
from api.tasks import cache_market, follow_send_payment
from control.models import BalanceLog
from control.tasks import compute_node_balance, do_accounting
from tests.node_utils import (
from tests.test_api import BaseAPITestCase
from tests.utils.node import (
add_invoice,
create_address,
pay_invoice,
set_up_regtest_network,
)
from tests.pgp_utils import sign_message
from tests.test_api import BaseAPITestCase
from tests.utils.pgp import sign_message
def read_file(file_path):
@ -358,8 +359,13 @@ class TradeTest(BaseAPITestCase):
def follow_hold_invoices(self):
# A background thread checks every 5 second the status of invoices. We invoke directly during test.
follow_invoices = FollowInvoices()
follow_invoices.follow_hold_invoices()
follower = FollowInvoices()
follower.follow_hold_invoices()
def clean_orders(self):
# A background thread checks every 5 second order expirations. We invoke directly during test.
cleaner = CleanOrders()
cleaner.clean_orders()
def send_payments(self):
# A background thread checks every 5 second whether there are outgoing payments. We invoke directly during test.
@ -906,6 +912,130 @@ class TradeTest(BaseAPITestCase):
data["bad_request"], "This order has been cancelled collaborativelly"
)
def test_created_order_expires(self):
"""
Tests the expiration of a public order
"""
maker_form = self.maker_form_buy_with_range
response = self.make_order(maker_form)
# Change order expiry to now
order = Order.objects.get(id=response.json()["id"])
order.expires_at = datetime.now()
order.save()
# Make orders expire
self.clean_orders()
response = self.get_order(response.json()["id"])
data = response.json()
self.assertEqual(response.status_code, 200)
self.assertResponse(response)
self.assertEqual(
data["status"],
Order.Status.EXP,
)
self.assertEqual(
data["expiry_message"],
Order.ExpiryReasons(Order.ExpiryReasons.NMBOND).label,
)
self.assertEqual(data["expiry_reason"], Order.ExpiryReasons.NMBOND)
def test_public_order_expires(self):
"""
Tests the expiration of a public order
"""
maker_form = self.maker_form_buy_with_range
response = self.make_and_publish_order(maker_form)
# Change order expiry to now
order = Order.objects.get(id=response.json()["id"])
order.expires_at = datetime.now()
order.save()
# Make orders expire
self.clean_orders()
response = self.get_order(response.json()["id"])
data = response.json()
self.assertEqual(response.status_code, 200)
self.assertResponse(response)
self.assertEqual(
data["status"],
Order.Status.EXP,
)
self.assertEqual(
data["expiry_message"],
Order.ExpiryReasons(Order.ExpiryReasons.NTAKEN).label,
)
self.assertEqual(data["expiry_reason"], Order.ExpiryReasons.NTAKEN)
def test_taken_order_expires(self):
"""
Tests the expiration of a public order
"""
maker_form = self.maker_form_buy_with_range
response = self.make_and_lock_contract(maker_form)
# Change order expiry to now
order = Order.objects.get(id=response.json()["id"])
order.expires_at = datetime.now()
order.save()
# Make orders expire
self.clean_orders()
response = self.get_order(response.json()["id"])
data = response.json()
self.assertEqual(response.status_code, 200)
self.assertResponse(response)
self.assertEqual(
data["status"],
Order.Status.EXP,
)
self.assertEqual(
data["expiry_message"],
Order.ExpiryReasons(Order.ExpiryReasons.NESINV).label,
)
self.assertEqual(data["expiry_reason"], Order.ExpiryReasons.NESINV)
def test_escrow_locked_expires(self):
"""
Tests the expiration of a public order
"""
maker_form = self.maker_form_buy_with_range
response = self.trade_to_locked_escrow(maker_form)
# Change order expiry to now
order = Order.objects.get(id=response.json()["id"])
order.expires_at = datetime.now()
order.save()
# Make orders expire
self.clean_orders()
response = self.get_order(response.json()["id"])
data = response.json()
self.assertEqual(response.status_code, 200)
self.assertResponse(response)
self.assertEqual(
data["status"],
Order.Status.EXP,
)
self.assertEqual(
data["expiry_message"],
Order.ExpiryReasons(Order.ExpiryReasons.NINVOI).label,
)
self.assertEqual(data["expiry_reason"], Order.ExpiryReasons.NINVOI)
def test_ticks(self):
"""
Tests the historical ticks serving endpoint after creating a contract

0
tests/utils/__init__.py Normal file
View File