chore: fix lint

This commit is contained in:
Vlad Stan
2026-03-30 13:12:46 +03:00
parent 22b4ab779f
commit c94cef07c2
16 changed files with 139 additions and 78 deletions
+1
View File
@@ -40,6 +40,7 @@ def get_random_string(iterations: int = 10):
async def get_random_invoice_data(): async def get_random_invoice_data():
return {"out": False, "amount": 10, "memo": f"test_memo_{get_random_string(10)}"} return {"out": False, "amount": 10, "memo": f"test_memo_{get_random_string(10)}"}
settings.lnbits_backend_wallet_class = "FakeWallet" settings.lnbits_backend_wallet_class = "FakeWallet"
set_funding_source("FakeWallet") set_funding_source("FakeWallet")
funding_source = get_funding_source() funding_source = get_funding_source()
+6 -2
View File
@@ -18,7 +18,9 @@ from lnbits.utils.exchange_rates import (
class MockResponse: class MockResponse:
def __init__(self, *, text: str = "", json_data=None, error: Exception | None = None): def __init__(
self, *, text: str = "", json_data=None, error: Exception | None = None
):
self.text = text self.text = text
self._json_data = json_data or {} self._json_data = json_data or {}
self._error = error self._error = error
@@ -263,7 +265,9 @@ async def test_btc_rates_skips_unsupported_and_failing_providers(
) )
client = MockAsyncClient(MockResponse(error=httpx.HTTPError("boom"))) client = MockAsyncClient(MockResponse(error=httpx.HTTPError("boom")))
mocker.patch.object(settings, "lnbits_allowed_currencies", []) mocker.patch.object(settings, "lnbits_allowed_currencies", [])
mocker.patch.object(settings, "lnbits_exchange_rate_providers", [unsupported, failing]) mocker.patch.object(
settings, "lnbits_exchange_rate_providers", [unsupported, failing]
)
mocker.patch("lnbits.utils.exchange_rates.httpx.AsyncClient", return_value=client) mocker.patch("lnbits.utils.exchange_rates.httpx.AsyncClient", return_value=client)
assert await btc_rates("usd") == [] assert await btc_rates("usd") == []
+7 -5
View File
@@ -17,9 +17,11 @@ from lnbits.core.services.fiat_providers import (
check_fiat_status, check_fiat_status,
check_stripe_signature, check_stripe_signature,
handle_fiat_payment_confirmation, handle_fiat_payment_confirmation,
test_connection as fiat_provider_connection,
verify_paypal_webhook, verify_paypal_webhook,
) )
from lnbits.core.services.fiat_providers import (
test_connection as fiat_provider_connection,
)
from lnbits.core.services.users import create_user_account from lnbits.core.services.users import create_user_account
from lnbits.fiat.base import FiatInvoiceResponse, FiatPaymentStatus, FiatStatusResponse from lnbits.fiat.base import FiatInvoiceResponse, FiatPaymentStatus, FiatStatusResponse
from lnbits.settings import Settings from lnbits.settings import Settings
@@ -577,9 +579,7 @@ async def test_verify_paypal_webhook_requires_headers(settings: Settings):
@pytest.mark.anyio @pytest.mark.anyio
async def test_verify_paypal_webhook_success( async def test_verify_paypal_webhook_success(settings: Settings, mocker: MockerFixture):
settings: Settings, mocker: MockerFixture
):
settings.paypal_webhook_id = "webhook-id" settings.paypal_webhook_id = "webhook-id"
client = MockHTTPClient( client = MockHTTPClient(
[ [
@@ -648,7 +648,9 @@ async def test_test_connection_reports_provider_status(mocker: MockerFixture):
assert missing_status.message == "Fiat provider 'stripe' not found." assert missing_status.message == "Fiat provider 'stripe' not found."
provider = mocker.Mock() provider = mocker.Mock()
provider.status = AsyncMock(return_value=FiatStatusResponse(error_message="bad key")) provider.status = AsyncMock(
return_value=FiatStatusResponse(error_message="bad key")
)
mocker.patch( mocker.patch(
"lnbits.core.services.fiat_providers.get_fiat_provider", "lnbits.core.services.fiat_providers.get_fiat_provider",
AsyncMock(return_value=provider), AsyncMock(return_value=provider),
+4 -1
View File
@@ -264,7 +264,10 @@ def test_path_and_case_helpers():
assert normalize_path("/upgrades/ext/assets/app.js") == "/assets/app.js" assert normalize_path("/upgrades/ext/assets/app.js") == "/assets/app.js"
assert normalize_endpoint("example.com/") == "https://example.com" assert normalize_endpoint("example.com/") == "https://example.com"
assert normalize_endpoint("ws://socket.example.com") == "ws://socket.example.com" assert normalize_endpoint("ws://socket.example.com") == "ws://socket.example.com"
assert normalize_endpoint("http://example.com/", add_proto=False) == "http://example.com" assert (
normalize_endpoint("http://example.com/", add_proto=False)
== "http://example.com"
)
assert camel_to_words("CamelCaseName") == "Camel Case Name" assert camel_to_words("CamelCaseName") == "Camel Case Name"
assert camel_to_snake("CamelCaseName") == "camel_case_name" assert camel_to_snake("CamelCaseName") == "camel_case_name"
+1 -1
View File
@@ -3,8 +3,8 @@ import json
import pytest import pytest
from lnbits.db import ( from lnbits.db import (
dict_to_submodel,
dict_to_model, dict_to_model,
dict_to_submodel,
insert_query, insert_query,
model_to_dict, model_to_dict,
update_query, update_query,
+30 -25
View File
@@ -1,10 +1,11 @@
from io import BytesIO from io import BytesIO
from types import SimpleNamespace
from uuid import uuid4 from uuid import uuid4
import pytest import pytest
from fastapi import UploadFile
from PIL import Image from PIL import Image
from pytest_mock.plugin import MockerFixture from pytest_mock.plugin import MockerFixture
from starlette.datastructures import Headers
from lnbits.core.crud import create_account from lnbits.core.crud import create_account
from lnbits.core.crud.assets import get_user_asset, get_user_assets_count from lnbits.core.crud.assets import get_user_asset, get_user_assets_count
@@ -19,24 +20,34 @@ async def _create_user() -> str:
return user_id return user_id
def _make_upload_file(
contents: bytes,
*,
filename: str,
content_type: str | None,
) -> UploadFile:
headers = (
Headers({"content-type": content_type}) if content_type is not None else None
)
return UploadFile(BytesIO(contents), filename=filename, headers=headers)
@pytest.mark.anyio @pytest.mark.anyio
async def test_create_user_asset_validates_upload_constraints( async def test_create_user_asset_validates_upload_constraints(
settings: Settings, mocker: MockerFixture settings: Settings, mocker: MockerFixture
): ):
file_without_type = SimpleNamespace( file_without_type = _make_upload_file(b"hello", filename="a.txt", content_type=None)
content_type=None,
filename="a.txt",
read=mocker.AsyncMock(return_value=b"hello"),
)
with pytest.raises(ValueError, match="File must have a content type."): with pytest.raises(ValueError, match="File must have a content type."):
await create_user_asset("user-1", file_without_type, is_public=False) await create_user_asset("user-1", file_without_type, is_public=False)
bad_type = SimpleNamespace( bad_type = _make_upload_file(
content_type="application/x-msdownload", b"hello",
filename="bad.bin", filename="bad.bin",
read=mocker.AsyncMock(return_value=b"hello"), content_type="application/x-msdownload",
) )
with pytest.raises(ValueError, match="File type 'application/x-msdownload' not allowed."): with pytest.raises(
ValueError, match="File type 'application/x-msdownload' not allowed."
):
await create_user_asset("user-1", bad_type, is_public=False) await create_user_asset("user-1", bad_type, is_public=False)
original_max_assets = settings.lnbits_max_assets_per_user original_max_assets = settings.lnbits_max_assets_per_user
@@ -47,27 +58,25 @@ async def test_create_user_asset_validates_upload_constraints(
settings.lnbits_max_asset_size_mb = 1 settings.lnbits_max_asset_size_mb = 1
settings.lnbits_assets_no_limit_users = [] settings.lnbits_assets_no_limit_users = []
limited_user = await _create_user() limited_user = await _create_user()
allowed_type = SimpleNamespace( allowed_type = _make_upload_file(
content_type="text/plain", b"hello", filename="ok.txt", content_type="text/plain"
filename="ok.txt",
read=mocker.AsyncMock(return_value=b"hello"),
) )
await create_user_asset(limited_user, allowed_type, is_public=False) await create_user_asset(limited_user, allowed_type, is_public=False)
blocked_by_count = SimpleNamespace( blocked_by_count = _make_upload_file(
content_type="text/plain", b"again",
filename="again.txt", filename="again.txt",
read=mocker.AsyncMock(return_value=b"again"), content_type="text/plain",
) )
with pytest.raises(ValueError, match="Max upload count of 1 exceeded."): with pytest.raises(ValueError, match="Max upload count of 1 exceeded."):
await create_user_asset(limited_user, blocked_by_count, is_public=False) await create_user_asset(limited_user, blocked_by_count, is_public=False)
settings.lnbits_max_asset_size_mb = 0.000001 settings.lnbits_max_asset_size_mb = 0.000001
oversized_user = await _create_user() oversized_user = await _create_user()
large_file = SimpleNamespace( large_file = _make_upload_file(
content_type="text/plain", b"0123456789",
filename="ok.txt", filename="ok.txt",
read=mocker.AsyncMock(return_value=b"0123456789"), content_type="text/plain",
) )
with pytest.raises(ValueError, match="File limit of 1e-06MB exceeded."): with pytest.raises(ValueError, match="File limit of 1e-06MB exceeded."):
await create_user_asset(oversized_user, large_file, is_public=False) await create_user_asset(oversized_user, large_file, is_public=False)
@@ -84,11 +93,7 @@ async def test_create_user_asset_success(mocker: MockerFixture):
"lnbits.core.services.assets.thumbnail_from_bytes", "lnbits.core.services.assets.thumbnail_from_bytes",
return_value=None, return_value=None,
) )
file = SimpleNamespace( file = _make_upload_file(b"hello", filename="hello.txt", content_type="text/plain")
content_type="text/plain",
filename="hello.txt",
read=mocker.AsyncMock(return_value=b"hello"),
)
asset = await create_user_asset(user_id, file, is_public=True) asset = await create_user_asset(user_id, file, is_public=True)
stored = await get_user_asset(user_id, asset.id) stored = await get_user_asset(user_id, asset.id)
+7 -4
View File
@@ -1,5 +1,5 @@
from uuid import uuid4
from types import SimpleNamespace from types import SimpleNamespace
from uuid import uuid4
import pytest import pytest
from pytest_mock.plugin import MockerFixture from pytest_mock.plugin import MockerFixture
@@ -8,7 +8,6 @@ from lnbits.core.crud import (
create_installed_extension, create_installed_extension,
delete_installed_extension, delete_installed_extension,
get_installed_extension, get_installed_extension,
get_installed_extensions,
) )
from lnbits.core.models.extensions import ( from lnbits.core.models.extensions import (
Extension, Extension,
@@ -57,7 +56,9 @@ def _installable_extension(
@pytest.mark.anyio @pytest.mark.anyio
async def test_install_extension_rejects_incompatible_release(tmp_path, settings: Settings): async def test_install_extension_rejects_incompatible_release(
tmp_path, settings: Settings
):
ext_info = _installable_extension(f"ext_{uuid4().hex[:8]}", compatible=False) ext_info = _installable_extension(f"ext_{uuid4().hex[:8]}", compatible=False)
original_data_folder = settings.lnbits_data_folder original_data_folder = settings.lnbits_data_folder
original_extensions_path = settings.lnbits_extensions_path original_extensions_path = settings.lnbits_extensions_path
@@ -293,7 +294,9 @@ async def test_get_valid_extensions_and_single_extension_respect_settings(
assert ext_id_one in valid_codes assert ext_id_one in valid_codes
assert ext_id_two not in valid_codes assert ext_id_two not in valid_codes
assert await get_valid_extension(ext_id_one, include_deactivated=True) is not None assert (
await get_valid_extension(ext_id_one, include_deactivated=True) is not None
)
settings.lnbits_extensions_deactivate_all = True settings.lnbits_extensions_deactivate_all = True
assert await get_valid_extensions(include_deactivated=False) == [] assert await get_valid_extensions(include_deactivated=False) == []
+4 -2
View File
@@ -1,4 +1,5 @@
from types import SimpleNamespace from types import SimpleNamespace
from typing import Any, cast
from uuid import uuid4 from uuid import uuid4
import pytest import pytest
@@ -139,10 +140,11 @@ async def test_check_server_balance_against_node_notifies_and_switches(
async def test_check_balance_delta_changed_tracks_and_notifies( async def test_check_balance_delta_changed_tracks_and_notifies(
settings: Settings, mocker: MockerFixture settings: Settings, mocker: MockerFixture
): ):
settings_any = cast(Any, settings)
original_latest = settings.latest_balance_delta_sats original_latest = settings.latest_balance_delta_sats
original_threshold = settings.notification_balance_delta_threshold_sats original_threshold = settings.notification_balance_delta_threshold_sats
try: try:
settings.latest_balance_delta_sats = None settings_any.latest_balance_delta_sats = None
settings.notification_balance_delta_threshold_sats = 3 settings.notification_balance_delta_threshold_sats = 3
mocker.patch( mocker.patch(
"lnbits.core.services.funding_source.get_balance_delta", "lnbits.core.services.funding_source.get_balance_delta",
@@ -165,5 +167,5 @@ async def test_check_balance_delta_changed_tracks_and_notifies(
enqueue.assert_called_once() enqueue.assert_called_once()
assert settings.latest_balance_delta_sats == 10 assert settings.latest_balance_delta_sats == 10
finally: finally:
settings.latest_balance_delta_sats = original_latest settings_any.latest_balance_delta_sats = original_latest
settings.notification_balance_delta_threshold_sats = original_threshold settings.notification_balance_delta_threshold_sats = original_threshold
+31 -13
View File
@@ -1,6 +1,7 @@
from uuid import uuid4 from uuid import uuid4
import pytest import pytest
from bolt11.types import MilliSatoshi
from lnurl import ( from lnurl import (
LnAddress, LnAddress,
LnurlErrorResponse, LnurlErrorResponse,
@@ -10,6 +11,8 @@ from lnurl import (
LnurlSuccessResponse, LnurlSuccessResponse,
LnurlWithdrawResponse, LnurlWithdrawResponse,
) )
from lnurl.types import CallbackUrl, LightningInvoice, LnurlPayMetadata
from pydantic import parse_obj_as
from pytest_mock.plugin import MockerFixture from pytest_mock.plugin import MockerFixture
from lnbits.core.crud import create_account, create_wallet, get_wallet from lnbits.core.crud import create_account, create_wallet, get_wallet
@@ -34,10 +37,12 @@ TEST_BOLT11 = (
def _make_pay_response() -> LnurlPayResponse: def _make_pay_response() -> LnurlPayResponse:
return LnurlPayResponse( return LnurlPayResponse(
callback="https://example.com/callback", callback=parse_obj_as(CallbackUrl, "https://example.com/callback"),
minSendable=1, minSendable=MilliSatoshi(1),
maxSendable=10_000, maxSendable=MilliSatoshi(10_000),
metadata='[["text/plain","Test"],["text/identifier","alice@example.com"]]', metadata=LnurlPayMetadata(
'[["text/plain","Test"],["text/identifier","alice@example.com"]]'
),
) )
@@ -60,10 +65,10 @@ async def _create_wallet() -> Wallet:
@pytest.mark.anyio @pytest.mark.anyio
async def test_perform_withdraw_success_and_validation(mocker: MockerFixture): async def test_perform_withdraw_success_and_validation(mocker: MockerFixture):
withdraw_response = LnurlWithdrawResponse( withdraw_response = LnurlWithdrawResponse(
callback="https://example.com/callback", callback=parse_obj_as(CallbackUrl, "https://example.com/callback"),
k1="k1", k1="k1",
minWithdrawable=1, minWithdrawable=MilliSatoshi(1),
maxWithdrawable=1000, maxWithdrawable=MilliSatoshi(1000),
defaultDescription="test", defaultDescription="test",
) )
execute_withdraw_mock = mocker.patch( execute_withdraw_mock = mocker.patch(
@@ -107,7 +112,9 @@ async def test_get_pr_from_lnurl_success_and_error(mocker: MockerFixture):
) )
mocker.patch( mocker.patch(
"lnbits.core.services.lnurl.execute_pay_request", "lnbits.core.services.lnurl.execute_pay_request",
mocker.AsyncMock(return_value=LnurlPayActionResponse(pr=TEST_BOLT11)), mocker.AsyncMock(
return_value=LnurlPayActionResponse(pr=LightningInvoice(TEST_BOLT11))
),
) )
assert await get_pr_from_lnurl("lnurl", 1000, comment="hello") == TEST_BOLT11 assert await get_pr_from_lnurl("lnurl", 1000, comment="hello") == TEST_BOLT11
@@ -125,7 +132,9 @@ async def test_fetch_lnurl_pay_request_converts_currency_and_stores_paylink(
mocker: MockerFixture, mocker: MockerFixture,
): ):
pay_response = _make_pay_response() pay_response = _make_pay_response()
action_response = LnurlPayActionResponse(pr=TEST_BOLT11, disposable=False) action_response = LnurlPayActionResponse(
pr=LightningInvoice(TEST_BOLT11), disposable=False
)
mocker.patch( mocker.patch(
"lnbits.core.services.lnurl.fiat_amount_as_satoshis", "lnbits.core.services.lnurl.fiat_amount_as_satoshis",
mocker.AsyncMock(return_value=100), mocker.AsyncMock(return_value=100),
@@ -146,8 +155,11 @@ async def test_fetch_lnurl_pay_request_converts_currency_and_stores_paylink(
assert response == pay_response assert response == pay_response
assert action == action_response assert action == action_response
execute_mock.assert_awaited_once() execute_mock.assert_awaited_once()
assert execute_mock.await_args is not None
assert execute_mock.await_args.kwargs["msat"] == 100_000 assert execute_mock.await_args.kwargs["msat"] == 100_000
store_paylink_mock.assert_awaited_once_with(pay_response, action_response, wallet, None) store_paylink_mock.assert_awaited_once_with(
pay_response, action_response, wallet, None
)
with pytest.raises(LnurlResponseException, match="No LNURL pay request provided."): with pytest.raises(LnurlResponseException, match="No LNURL pay request provided."):
await fetch_lnurl_pay_request(CreateLnurlPayment(amount=1)) await fetch_lnurl_pay_request(CreateLnurlPayment(amount=1))
@@ -157,9 +169,13 @@ async def test_fetch_lnurl_pay_request_converts_currency_and_stores_paylink(
async def test_store_paylink_appends_and_updates_existing(): async def test_store_paylink_appends_and_updates_existing():
wallet = await _create_wallet() wallet = await _create_wallet()
pay_response = _make_pay_response() pay_response = _make_pay_response()
action_response = LnurlPayActionResponse(pr=TEST_BOLT11, disposable=False) action_response = LnurlPayActionResponse(
pr=LightningInvoice(TEST_BOLT11), disposable=False
)
await store_paylink(pay_response, action_response, wallet, LnAddress("alice@example.com")) await store_paylink(
pay_response, action_response, wallet, LnAddress("alice@example.com")
)
stored_wallet = await get_wallet(wallet.id) stored_wallet = await get_wallet(wallet.id)
assert stored_wallet is not None assert stored_wallet is not None
@@ -167,7 +183,9 @@ async def test_store_paylink_appends_and_updates_existing():
assert stored_wallet.stored_paylinks.links[0].lnurl == "alice@example.com" assert stored_wallet.stored_paylinks.links[0].lnurl == "alice@example.com"
first_used = stored_wallet.stored_paylinks.links[0].last_used first_used = stored_wallet.stored_paylinks.links[0].last_used
await store_paylink(pay_response, action_response, wallet, LnAddress("alice@example.com")) await store_paylink(
pay_response, action_response, wallet, LnAddress("alice@example.com")
)
stored_wallet = await get_wallet(wallet.id) stored_wallet = await get_wallet(wallet.id)
assert stored_wallet is not None assert stored_wallet is not None
-3
View File
@@ -1,6 +1,3 @@
from types import SimpleNamespace
import httpx
import pytest import pytest
from pytest_mock.plugin import MockerFixture from pytest_mock.plugin import MockerFixture
+15 -5
View File
@@ -1,5 +1,4 @@
import asyncio import asyncio
from datetime import datetime, timezone
from http import HTTPStatus from http import HTTPStatus
from types import SimpleNamespace from types import SimpleNamespace
from unittest.mock import MagicMock from unittest.mock import MagicMock
@@ -7,8 +6,8 @@ from uuid import uuid4
import httpx import httpx
import pytest import pytest
from pywebpush import WebPushException
from pytest_mock.plugin import MockerFixture from pytest_mock.plugin import MockerFixture
from pywebpush import WebPushException
from lnbits.core.crud import ( from lnbits.core.crud import (
create_account, create_account,
@@ -37,9 +36,9 @@ from lnbits.core.services.notifications import (
send_chat_payment_notification, send_chat_payment_notification,
send_email, send_email,
send_email_notification, send_email_notification,
send_notification,
send_nostr_notification, send_nostr_notification,
send_nostr_notifications, send_nostr_notifications,
send_notification,
send_payment_notification, send_payment_notification,
send_payment_push_notification, send_payment_push_notification,
send_push_notification, send_push_notification,
@@ -118,7 +117,9 @@ async def _create_payment(
@pytest.mark.anyio @pytest.mark.anyio
async def test_enqueue_and_process_notifications(settings: Settings, mocker: MockerFixture): async def test_enqueue_and_process_notifications(
settings: Settings, mocker: MockerFixture
):
queue: asyncio.Queue = asyncio.Queue() queue: asyncio.Queue = asyncio.Queue()
admin_mock = mocker.patch( admin_mock = mocker.patch(
"lnbits.core.services.notifications.send_admin_notification", "lnbits.core.services.notifications.send_admin_notification",
@@ -138,6 +139,7 @@ async def test_enqueue_and_process_notifications(settings: Settings, mocker: Moc
await process_next_notification() await process_next_notification()
assert admin_mock.await_count == 1 assert admin_mock.await_count == 1
assert admin_mock.await_args is not None
assert admin_mock.await_args.args[0].startswith(f"[{settings.lnbits_site_title}]") assert admin_mock.await_args.args[0].startswith(f"[{settings.lnbits_site_title}]")
assert "alice" in admin_mock.await_args.args[0] assert "alice" in admin_mock.await_args.args[0]
assert admin_mock.await_args.args[1] == NotificationType.settings_update.value assert admin_mock.await_args.args[1] == NotificationType.settings_update.value
@@ -151,6 +153,7 @@ async def test_enqueue_and_process_notifications(settings: Settings, mocker: Moc
await process_next_notification() await process_next_notification()
assert user_mock.await_count == 1 assert user_mock.await_count == 1
assert user_mock.await_args is not None
assert user_mock.await_args.args[0] == user_notifications assert user_mock.await_args.args[0] == user_notifications
assert "hello" in user_mock.await_args.args[1] assert "hello" in user_mock.await_args.args[1]
assert user_mock.await_args.args[2] == NotificationType.text_message.value assert user_mock.await_args.args[2] == NotificationType.text_message.value
@@ -405,6 +408,7 @@ async def test_dispatch_webhook_marks_missing_invalid_and_failed_requests(
assert (await get_payment(payment.checking_id)).webhook_status == "-1" assert (await get_payment(payment.checking_id)).webhook_status == "-1"
invalid_payment = await _create_payment(wallet, webhook="https://invalid.example") invalid_payment = await _create_payment(wallet, webhook="https://invalid.example")
assert invalid_payment.webhook is not None
invalid_client = MockHTTPClient( invalid_client = MockHTTPClient(
post_response=httpx.Response( post_response=httpx.Response(
200, 200,
@@ -422,9 +426,13 @@ async def test_dispatch_webhook_marks_missing_invalid_and_failed_requests(
) )
await dispatch_webhook(invalid_payment) await dispatch_webhook(invalid_payment)
assert (await get_payment(invalid_payment.checking_id)).webhook_status in {"-1", "200"} assert (await get_payment(invalid_payment.checking_id)).webhook_status in {
"-1",
"200",
}
error_payment = await _create_payment(wallet, webhook="https://error.example") error_payment = await _create_payment(wallet, webhook="https://error.example")
assert error_payment.webhook is not None
mocker.patch( mocker.patch(
"lnbits.core.services.notifications.check_callback_url", "lnbits.core.services.notifications.check_callback_url",
return_value=None, return_value=None,
@@ -443,6 +451,7 @@ async def test_dispatch_webhook_marks_missing_invalid_and_failed_requests(
assert (await get_payment(error_payment.checking_id)).webhook_status == "500" assert (await get_payment(error_payment.checking_id)).webhook_status == "500"
request_payment = await _create_payment(wallet, webhook="https://request.example") request_payment = await _create_payment(wallet, webhook="https://request.example")
assert request_payment.webhook is not None
mocker.patch( mocker.patch(
"lnbits.core.services.notifications.httpx.AsyncClient", "lnbits.core.services.notifications.httpx.AsyncClient",
return_value=MockHTTPClient( return_value=MockHTTPClient(
@@ -574,6 +583,7 @@ async def test_send_payment_push_notification_and_cleanup_gone_subscriptions(
await send_payment_push_notification(wallet, payment) await send_payment_push_notification(wallet, payment)
assert send_push_mock.await_args is not None
assert send_push_mock.await_args.args[0].endpoint == subscription.endpoint assert send_push_mock.await_args.args[0].endpoint == subscription.endpoint
assert send_push_mock.await_args.args[1] == f"LNbits: {wallet.name}" assert send_push_mock.await_args.args[1] == f"LNbits: {wallet.name}"
assert "received 2 sats" in send_push_mock.await_args.args[2] assert "received 2 sats" in send_push_mock.await_args.args[2]
+11 -5
View File
@@ -17,13 +17,12 @@ from lnbits.core.models import (
Account, Account,
CreateInvoice, CreateInvoice,
CreatePayment, CreatePayment,
PaymentDailyStats,
PaymentState, PaymentState,
Wallet, Wallet,
) )
from lnbits.core.services.payments import ( from lnbits.core.services.payments import (
cancel_hold_invoice,
calculate_fiat_amounts, calculate_fiat_amounts,
cancel_hold_invoice,
check_payment_status, check_payment_status,
check_pending_payments, check_pending_payments,
check_time_limit_between_transactions, check_time_limit_between_transactions,
@@ -55,7 +54,9 @@ def _account() -> Account:
async def _create_wallet() -> Wallet: async def _create_wallet() -> Wallet:
account = _account() account = _account()
await create_account(account) await create_account(account)
return await create_wallet(user_id=account.id, wallet_name=f"wallet_{account.id[:8]}") return await create_wallet(
user_id=account.id, wallet_name=f"wallet_{account.id[:8]}"
)
async def _create_payment( async def _create_payment(
@@ -103,7 +104,10 @@ async def test_create_payment_request_routes_by_invoice_type(mocker: MockerFixtu
mocker.AsyncMock(return_value=fiat_payment), mocker.AsyncMock(return_value=fiat_payment),
) )
assert await create_payment_request("wallet-1", CreateInvoice(amount=1)) == wallet_payment assert (
await create_payment_request("wallet-1", CreateInvoice(amount=1))
== wallet_payment
)
assert ( assert (
await create_payment_request( await create_payment_request(
"wallet-1", "wallet-1",
@@ -165,7 +169,9 @@ async def test_check_pending_payments_skips_voidwallet_and_updates_recent_items(
"lnbits.core.services.payments.get_funding_source", "lnbits.core.services.payments.get_funding_source",
return_value=VoidWallet(), return_value=VoidWallet(),
) )
sleep_mock = mocker.patch("lnbits.core.services.payments.asyncio.sleep", mocker.AsyncMock()) sleep_mock = mocker.patch(
"lnbits.core.services.payments.asyncio.sleep", mocker.AsyncMock()
)
await check_pending_payments() await check_pending_payments()
sleep_mock.assert_not_awaited() sleep_mock.assert_not_awaited()
+8 -2
View File
@@ -2,7 +2,11 @@ import pytest
from pydantic import ValidationError from pydantic import ValidationError
from pytest_mock.plugin import MockerFixture from pytest_mock.plugin import MockerFixture
from lnbits.core.crud import create_admin_settings, delete_admin_settings, get_super_settings from lnbits.core.crud import (
create_admin_settings,
delete_admin_settings,
get_super_settings,
)
from lnbits.core.crud.settings import get_settings_field from lnbits.core.crud.settings import get_settings_field
from lnbits.core.services.settings import ( from lnbits.core.services.settings import (
check_webpush_settings, check_webpush_settings,
@@ -84,7 +88,9 @@ async def test_check_webpush_settings_generates_and_persists_keys(
settings.lnbits_webpush_pubkey = None settings.lnbits_webpush_pubkey = None
settings.lnbits_admin_ui = True settings.lnbits_admin_ui = True
mocker.patch("lnbits.core.services.settings.Vapid", return_value=FakeVapid()) mocker.patch("lnbits.core.services.settings.Vapid", return_value=FakeVapid())
mocker.patch("lnbits.core.services.settings.b64urlencode", return_value="public-key") mocker.patch(
"lnbits.core.services.settings.b64urlencode", return_value="public-key"
)
try: try:
await check_webpush_settings() await check_webpush_settings()
+8 -4
View File
@@ -15,7 +15,8 @@ from lnbits.core.crud import (
from lnbits.core.crud.settings import get_settings_field, set_settings_field from lnbits.core.crud.settings import get_settings_field, set_settings_field
from lnbits.core.models import Account from lnbits.core.models import Account
from lnbits.core.models.extensions import UserExtension from lnbits.core.models.extensions import UserExtension
from lnbits.core.models.users import RegisterUser, UserExtra from lnbits.core.models.users import RegisterUser
from lnbits.core.services.settings import update_cached_settings
from lnbits.core.services.users import ( from lnbits.core.services.users import (
check_admin_settings, check_admin_settings,
check_register_activation_settings, check_register_activation_settings,
@@ -25,7 +26,6 @@ from lnbits.core.services.users import (
update_user_account, update_user_account,
update_user_extensions, update_user_extensions,
) )
from lnbits.core.services.settings import update_cached_settings
from lnbits.settings import Settings from lnbits.settings import Settings
@@ -219,7 +219,9 @@ async def test_update_user_extensions_toggles_existing_and_creates_missing(
finally: finally:
settings.lnbits_user_default_extensions = original_default_exts settings.lnbits_user_default_extensions = original_default_exts
await create_user_extension(UserExtension(user=user.id, extension="keep", active=True)) await create_user_extension(
UserExtension(user=user.id, extension="keep", active=True)
)
await create_user_extension( await create_user_extension(
UserExtension(user=user.id, extension="enable", active=False) UserExtension(user=user.id, extension="enable", active=False)
) )
@@ -360,7 +362,9 @@ async def test_check_register_activation_settings_handles_invitation_codes(
is None is None
) )
assert one_time not in settings.lnbits_register_one_time_activation_codes assert one_time not in settings.lnbits_register_one_time_activation_codes
stored_codes = await get_settings_field("lnbits_register_one_time_activation_codes") stored_codes = await get_settings_field(
"lnbits_register_one_time_activation_codes"
)
assert stored_codes is not None assert stored_codes is not None
assert stored_codes.value == [] assert stored_codes.value == []
+4 -4
View File
@@ -1,7 +1,7 @@
import asyncio from typing import cast
import pytest import pytest
from fastapi import WebSocketDisconnect from fastapi import WebSocket, WebSocketDisconnect
from pytest_mock.plugin import MockerFixture from pytest_mock.plugin import MockerFixture
from lnbits.core.services.websockets import ( from lnbits.core.services.websockets import (
@@ -37,7 +37,7 @@ async def test_websocket_connection_manager_connect_and_send():
manager = WebsocketConnectionManager() manager = WebsocketConnectionManager()
websocket = FakeWebSocket() websocket = FakeWebSocket()
conn = await manager.connect("item-1", websocket) conn = await manager.connect("item-1", cast(WebSocket, websocket))
await manager.send("item-1", "payload") await manager.send("item-1", "payload")
assert websocket.accepted is True assert websocket.accepted is True
@@ -52,7 +52,7 @@ async def test_websocket_connection_manager_listen_queues_messages_and_disconnec
): ):
manager = WebsocketConnectionManager() manager = WebsocketConnectionManager()
websocket = FakeWebSocket(["hello", WebSocketDisconnect()]) websocket = FakeWebSocket(["hello", WebSocketDisconnect()])
conn = await manager.connect("item-2", websocket) conn = await manager.connect("item-2", cast(WebSocket, websocket))
original_running = settings.lnbits_running original_running = settings.lnbits_running
try: try:
settings.lnbits_running = True settings.lnbits_running = True
+2 -2
View File
@@ -328,7 +328,7 @@ def test_public_settings_from_settings(settings: Settings):
def test_set_cli_settings_updates_runtime_settings(settings: Settings): def test_set_cli_settings_updates_runtime_settings(settings: Settings):
original_host = settings.host original_host = settings.host
try: try:
set_cli_settings(host="0.0.0.0") set_cli_settings(host="0.0.0.0") # noqa S104
assert settings.host == "0.0.0.0" assert settings.host == "0.0.0.0" # noqa S104
finally: finally:
settings.host = original_host settings.host = original_host