mirror of
https://github.com/RoboSats/robosats.git
synced 2025-01-18 12:11:35 +00:00
Add order expiry tests
This commit is contained in:
parent
14340fd64b
commit
62ef86f1b4
@ -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")
|
||||
|
@ -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
0
tests/utils/__init__.py
Normal file
Loading…
Reference in New Issue
Block a user