From 40ffa7dea0785f49c88b3eddabc936e81e396e34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?dni=20=E2=9A=A1?= Date: Wed, 7 Aug 2024 16:19:53 +0200 Subject: [PATCH] test: refactor to not use paid_invoices stream for real invoice tests (#2628) --- lnbits/core/crud.py | 1 - lnbits/tasks.py | 2 + tests/helpers.py | 4 ++ tests/regtest/test_real_invoice.py | 103 +++++++++++++---------------- tests/regtest/test_x_node_api.py | 3 +- 5 files changed, 55 insertions(+), 58 deletions(-) diff --git a/lnbits/core/crud.py b/lnbits/core/crud.py index 474fca830..39fbad93b 100644 --- a/lnbits/core/crud.py +++ b/lnbits/core/crud.py @@ -972,7 +972,6 @@ async def update_payment_details( f"UPDATE apipayments SET {', '.join(set_clause)} WHERE checking_id = ?", tuple(set_variables), ) - return async def update_payment_extra( diff --git a/lnbits/tasks.py b/lnbits/tasks.py index e435fabb9..f926c8918 100644 --- a/lnbits/tasks.py +++ b/lnbits/tasks.py @@ -217,6 +217,8 @@ async def invoice_callback_dispatcher(checking_id: str, is_internal: bool = Fals preimage=status.preimage, status=PaymentState.SUCCESS, ) + payment = await get_standalone_payment(checking_id, incoming=True) + assert payment, "updated payment not found" internal = "internal" if is_internal else "" logger.success(f"{internal} invoice {checking_id} settled") for name, send_chan in invoice_listeners.items(): diff --git a/tests/helpers.py b/tests/helpers.py index 59a109f03..ebb5ac1b3 100644 --- a/tests/helpers.py +++ b/tests/helpers.py @@ -10,6 +10,10 @@ from lnbits.db import DB_TYPE, POSTGRES, FromRowModel from lnbits.wallets import get_funding_source, set_funding_source +class FakeError(Exception): + pass + + class DbTestModel(FromRowModel): id: int name: str diff --git a/tests/regtest/test_real_invoice.py b/tests/regtest/test_real_invoice.py index f537f1caf..6ecb9bae2 100644 --- a/tests/regtest/test_real_invoice.py +++ b/tests/regtest/test_real_invoice.py @@ -7,9 +7,10 @@ from lnbits import bolt11 from lnbits.core.crud import get_standalone_payment, update_payment_details from lnbits.core.models import CreateInvoice, Payment, PaymentState from lnbits.core.services import fee_reserve_total, get_balance_delta +from lnbits.tasks import create_task, wait_for_paid_invoices from lnbits.wallets import get_funding_source -from ..helpers import is_fake, is_regtest +from ..helpers import FakeError, is_fake, is_regtest from .helpers import ( cancel_invoice, get_real_invoice, @@ -79,33 +80,30 @@ async def test_create_real_invoice(client, adminkey_headers_from, inkey_headers_ payment_status = response.json() assert not payment_status["paid"] - async def listen(): - async for checking_id in get_funding_source().paid_invoices_stream(): - if checking_id == invoice["checking_id"]: - # wait for the backend to update the payment status - await asyncio.sleep(3) - return checking_id + async def on_paid(payment: Payment): + + assert payment.checking_id == invoice["payment_hash"] + + response = await client.get( + f'/api/v1/payments/{invoice["payment_hash"]}', headers=inkey_headers_from + ) + assert response.status_code < 300 + payment_status = response.json() + assert payment_status["paid"] - async def pay(): - # wait a sec to paid_invoices_stream to start listening await asyncio.sleep(1) - pay_real_invoice(invoice["payment_request"]) - return True + balance = await get_node_balance_sats() + assert balance - prev_balance == create_invoice.amount - checking_id, paid = await asyncio.gather(listen(), pay()) - assert paid - assert checking_id == invoice["payment_hash"] + # exit out of infinite loop + raise FakeError() - response = await client.get( - f'/api/v1/payments/{invoice["payment_hash"]}', headers=inkey_headers_from - ) - assert response.status_code < 300 - payment_status = response.json() - assert payment_status["paid"] + task = create_task(wait_for_paid_invoices("test_create_invoice", on_paid)()) + pay_real_invoice(invoice["payment_request"]) - await asyncio.sleep(1) - balance = await get_node_balance_sats() - assert balance - prev_balance == create_invoice.amount + # wait for the task to exit + with pytest.raises(FakeError): + await task @pytest.mark.asyncio @@ -298,45 +296,38 @@ async def test_receive_real_invoice_set_pending_and_check_state( payment_status = response.json() assert not payment_status["paid"] - async def listen(): - async for checking_id in get_funding_source().paid_invoices_stream(): - if checking_id == invoice["checking_id"]: - # wait for the backend to update the payment status - await asyncio.sleep(3) - return checking_id + async def on_paid(payment: Payment): + assert payment.checking_id == invoice["payment_hash"] - async def pay(): - # wait a sec to paid_invoices_stream to start listening - await asyncio.sleep(1) - pay_real_invoice(invoice["payment_request"]) - return True + response = await client.get( + f'/api/v1/payments/{invoice["payment_hash"]}', headers=inkey_headers_from + ) + assert response.status_code < 300 + payment_status = response.json() + assert payment_status["paid"] - checking_id, paid = await asyncio.gather(listen(), pay()) - assert paid - assert checking_id == invoice["payment_hash"] + assert payment + assert payment.pending is False - response = await client.get( - f'/api/v1/payments/{invoice["payment_hash"]}', headers=inkey_headers_from - ) - assert response.status_code < 300 - payment_status = response.json() - assert payment_status["paid"] + # set the incoming invoice to pending + await update_payment_details(payment.checking_id, status=PaymentState.PENDING) - # get the incoming payment from the db - payment = await get_standalone_payment(invoice["payment_hash"], incoming=True) - assert payment - assert payment.pending is False + payment_pending = await get_standalone_payment( + invoice["payment_hash"], incoming=True + ) + assert payment_pending + assert payment_pending.pending is True + assert payment_pending.success is False + assert payment_pending.failed is False - # set the incoming invoice to pending - await update_payment_details(payment.checking_id, status=PaymentState.PENDING) + # exit out of infinite loop + raise FakeError() - payment_pending = await get_standalone_payment( - invoice["payment_hash"], incoming=True - ) - assert payment_pending - assert payment_pending.pending is True - assert payment_pending.success is False - assert payment_pending.failed is False + task = create_task(wait_for_paid_invoices("test_create_invoice", on_paid)()) + pay_real_invoice(invoice["payment_request"]) + + with pytest.raises(FakeError): + await task @pytest.mark.asyncio diff --git a/tests/regtest/test_x_node_api.py b/tests/regtest/test_x_node_api.py index 30a6b6e95..9de7394b0 100644 --- a/tests/regtest/test_x_node_api.py +++ b/tests/regtest/test_x_node_api.py @@ -160,7 +160,8 @@ async def test_peer_management(node_client): response = await node_client.delete(f"/node/api/v1/peers/{peer_id}") assert response.status_code == 200 - await asyncio.sleep(0.1) + # lndrest is slow to remove the peer + await asyncio.sleep(0.3) response = await node_client.get("/node/api/v1/peers") assert response.status_code == 200