refactor: extract helpers, move private functions to the bottom
This commit is contained in:
@@ -1,39 +1,11 @@
|
||||
from io import BytesIO
|
||||
from uuid import uuid4
|
||||
|
||||
import pytest
|
||||
from fastapi import UploadFile
|
||||
from httpx import AsyncClient
|
||||
from PIL import Image
|
||||
from starlette.datastructures import Headers
|
||||
|
||||
from lnbits.core.crud.assets import get_user_asset
|
||||
from lnbits.core.services.assets import create_user_asset
|
||||
|
||||
|
||||
def _png_bytes() -> bytes:
|
||||
image = Image.new("RGB", (32, 32), color="blue")
|
||||
buffer = BytesIO()
|
||||
image.save(buffer, format="PNG")
|
||||
return buffer.getvalue()
|
||||
|
||||
|
||||
def _upload_file(contents: bytes, filename: str, content_type: str) -> UploadFile:
|
||||
return UploadFile(
|
||||
BytesIO(contents),
|
||||
filename=filename,
|
||||
headers=Headers({"content-type": content_type}),
|
||||
)
|
||||
|
||||
|
||||
async def _user_headers(client: AsyncClient, user_id: str) -> dict[str, str]:
|
||||
response = await client.post("/api/v1/auth/usr", json={"usr": user_id})
|
||||
client.cookies.clear()
|
||||
access_token = response.json()["access_token"]
|
||||
return {
|
||||
"Authorization": f"Bearer {access_token}",
|
||||
"Content-type": "application/json",
|
||||
}
|
||||
from tests.helpers import get_png_bytes, get_user_token_headers, make_upload_file
|
||||
|
||||
|
||||
@pytest.mark.anyio
|
||||
@@ -100,10 +72,14 @@ async def test_asset_api_enforces_visibility_and_supports_admin_updates(
|
||||
):
|
||||
private_asset = await create_user_asset(
|
||||
from_user.id,
|
||||
_upload_file(_png_bytes(), f"private_{uuid4().hex[:8]}.png", "image/png"),
|
||||
make_upload_file(
|
||||
get_png_bytes(),
|
||||
filename=f"private_{uuid4().hex[:8]}.png",
|
||||
content_type="image/png",
|
||||
),
|
||||
is_public=False,
|
||||
)
|
||||
other_user_headers = await _user_headers(client, to_user.id)
|
||||
other_user_headers = await get_user_token_headers(client, to_user.id)
|
||||
|
||||
anonymous = await client.get(f"/api/v1/assets/{private_asset.id}/data")
|
||||
assert anonymous.status_code == 404
|
||||
@@ -152,7 +128,7 @@ async def test_asset_api_validates_uploads_and_missing_assets(
|
||||
|
||||
stored = await create_user_asset(
|
||||
"missing-user-check",
|
||||
_upload_file(b"content", "content.txt", "text/plain"),
|
||||
make_upload_file(b"content", filename="content.txt", content_type="text/plain"),
|
||||
is_public=True,
|
||||
)
|
||||
fetched = await get_user_asset("missing-user-check", stored.id)
|
||||
|
||||
@@ -19,7 +19,6 @@ from lnbits.core.models.extensions import (
|
||||
CreateExtensionReview,
|
||||
Extension,
|
||||
ExtensionConfig,
|
||||
ExtensionMeta,
|
||||
ExtensionRelease,
|
||||
InstallableExtension,
|
||||
PayToEnableInfo,
|
||||
@@ -49,45 +48,7 @@ from lnbits.core.views.extension_api import (
|
||||
get_pay_to_enable_invoice,
|
||||
get_pay_to_install_invoice,
|
||||
)
|
||||
|
||||
|
||||
def _release(ext_id: str, version: str = "1.0.0") -> ExtensionRelease:
|
||||
return ExtensionRelease(
|
||||
name=ext_id,
|
||||
version=version,
|
||||
archive=f"https://example.com/{ext_id}.zip",
|
||||
source_repo="org/repo",
|
||||
hash=f"hash-{ext_id}",
|
||||
details_link=f"https://example.com/{ext_id}/details.json",
|
||||
repo=f"https://github.com/org/{ext_id}",
|
||||
icon=f"/{ext_id}/static/icon.png",
|
||||
pay_link=f"https://pay.example/{ext_id}",
|
||||
)
|
||||
|
||||
|
||||
def _installable_extension(
|
||||
ext_id: str,
|
||||
*,
|
||||
active: bool = True,
|
||||
pay_to_enable: PayToEnableInfo | None = None,
|
||||
dependencies: list[str] | None = None,
|
||||
payments: list[ReleasePaymentInfo] | None = None,
|
||||
) -> InstallableExtension:
|
||||
release = _release(ext_id)
|
||||
return InstallableExtension(
|
||||
id=ext_id,
|
||||
name=f"Extension {ext_id}",
|
||||
version=release.version,
|
||||
active=active,
|
||||
short_description="Demo extension",
|
||||
icon=release.icon,
|
||||
meta=ExtensionMeta(
|
||||
installed_release=release,
|
||||
pay_to_enable=pay_to_enable,
|
||||
dependencies=dependencies or [],
|
||||
payments=payments or [],
|
||||
),
|
||||
)
|
||||
from tests.helpers import make_extension_release, make_installable_extension
|
||||
|
||||
|
||||
class _MockHTTPResponse:
|
||||
@@ -132,7 +93,7 @@ class _MockHTTPClient:
|
||||
@pytest.mark.anyio
|
||||
async def test_extension_api_install_details_and_release_endpoints(mocker):
|
||||
ext_id = f"ext_{uuid4().hex[:8]}"
|
||||
release = _release(ext_id)
|
||||
release = make_extension_release(ext_id)
|
||||
create_data = CreateExtension(
|
||||
ext_id=ext_id,
|
||||
archive=release.archive,
|
||||
@@ -172,7 +133,7 @@ async def test_extension_api_install_details_and_release_endpoints(mocker):
|
||||
assert details["icon"] == release.icon
|
||||
assert details["repo"] == release.repo
|
||||
|
||||
installed_ext = _installable_extension(
|
||||
installed_ext = make_installable_extension(
|
||||
ext_id,
|
||||
payments=[
|
||||
ReleasePaymentInfo(
|
||||
@@ -218,7 +179,7 @@ async def test_extension_api_pay_to_enable_and_catalog_views(mocker, admin_user)
|
||||
|
||||
ext_id = f"paid_{uuid4().hex[:8]}"
|
||||
await create_installed_extension(
|
||||
_installable_extension(
|
||||
make_installable_extension(
|
||||
ext_id,
|
||||
pay_to_enable=PayToEnableInfo(
|
||||
required=True, amount=10, wallet=admin_wallet.id
|
||||
@@ -294,7 +255,7 @@ async def test_extension_api_pay_to_enable_and_catalog_views(mocker, admin_user)
|
||||
visible_extensions = await api_get_user_extensions(AccountId(id=regular_user.id))
|
||||
assert [ext.code for ext in visible_extensions] == [ext_id]
|
||||
|
||||
catalog_entry = _installable_extension(
|
||||
catalog_entry = make_installable_extension(
|
||||
ext_id,
|
||||
pay_to_enable=PayToEnableInfo(required=True, amount=21, wallet=admin_wallet.id),
|
||||
)
|
||||
@@ -315,11 +276,11 @@ async def test_extension_api_activate_uninstall_install_invoice_and_cleanup(mock
|
||||
uninstall_ext = f"uninstall_{uuid4().hex[:8]}"
|
||||
db_ext = f"db_{uuid4().hex[:8]}"
|
||||
|
||||
await create_installed_extension(_installable_extension(base_ext))
|
||||
await create_installed_extension(make_installable_extension(base_ext))
|
||||
await create_installed_extension(
|
||||
_installable_extension(dependent_ext, dependencies=[base_ext])
|
||||
make_installable_extension(dependent_ext, dependencies=[base_ext])
|
||||
)
|
||||
await create_installed_extension(_installable_extension(uninstall_ext))
|
||||
await create_installed_extension(make_installable_extension(uninstall_ext))
|
||||
|
||||
mocker.patch(
|
||||
"lnbits.core.views.extension_api.get_valid_extensions",
|
||||
@@ -370,7 +331,7 @@ async def test_extension_api_activate_uninstall_install_invoice_and_cleanup(mock
|
||||
install_invoice = await create_wallet_invoice(
|
||||
wallet.id, CreateInvoice(out=False, amount=33, memo="install extension")
|
||||
)
|
||||
release = _release(base_ext, version="2.0.0")
|
||||
release = make_extension_release(base_ext, version="2.0.0")
|
||||
payment_info = ReleasePaymentInfo(
|
||||
amount=33,
|
||||
pay_link=release.pay_link,
|
||||
|
||||
@@ -7,19 +7,8 @@ from lnbits.core.crud.extensions import create_user_extension, get_user_extensio
|
||||
from lnbits.core.crud.users import get_account
|
||||
from lnbits.core.models.extensions import (
|
||||
Extension,
|
||||
ExtensionRelease,
|
||||
UserExtension,
|
||||
)
|
||||
from lnbits.core.models.extensions_builder import (
|
||||
ActionFields,
|
||||
ClientDataFields,
|
||||
DataField,
|
||||
DataFields,
|
||||
ExtensionData,
|
||||
OwnerDataFields,
|
||||
PublicPageFields,
|
||||
SettingsFields,
|
||||
)
|
||||
from lnbits.core.models.users import AccountId
|
||||
from lnbits.core.views.extensions_builder_api import (
|
||||
api_build_extension,
|
||||
@@ -28,41 +17,7 @@ from lnbits.core.views.extensions_builder_api import (
|
||||
api_preview_extension,
|
||||
)
|
||||
from lnbits.settings import Settings
|
||||
|
||||
|
||||
def _extension_data(ext_id: str = "demoext") -> ExtensionData:
|
||||
return ExtensionData(
|
||||
id=ext_id,
|
||||
name="Demo Extension",
|
||||
stub_version="0.1.0",
|
||||
short_description="Generated extension",
|
||||
owner_data=DataFields(
|
||||
name="OwnerData",
|
||||
fields=[DataField(name="wallet_id", type="wallet")],
|
||||
),
|
||||
client_data=DataFields(
|
||||
name="ClientData",
|
||||
fields=[DataField(name="amount", type="int")],
|
||||
),
|
||||
settings_data=SettingsFields(name="SettingsData", fields=[]),
|
||||
public_page=PublicPageFields(
|
||||
owner_data_fields=OwnerDataFields(),
|
||||
client_data_fields=ClientDataFields(),
|
||||
action_fields=ActionFields(),
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
def _release(ext_id: str) -> ExtensionRelease:
|
||||
return ExtensionRelease(
|
||||
name=ext_id,
|
||||
version="0.1.0",
|
||||
archive=f"https://example.com/{ext_id}.zip",
|
||||
source_repo="org/repo",
|
||||
is_github_release=False,
|
||||
hash=f"hash-{ext_id}",
|
||||
icon=f"/{ext_id}/static/image/{ext_id}.png",
|
||||
)
|
||||
from tests.helpers import make_extension_data, make_extension_release
|
||||
|
||||
|
||||
@pytest.mark.anyio
|
||||
@@ -70,7 +25,7 @@ async def test_extensions_builder_api_build_preview_and_cleanup(
|
||||
tmp_path, settings: Settings, mocker, from_user
|
||||
):
|
||||
ext_id = f"builder_{uuid4().hex[:8]}"
|
||||
data = _extension_data(ext_id)
|
||||
data = make_extension_data(ext_id)
|
||||
build_dir = tmp_path / "build"
|
||||
build_dir.mkdir(parents=True, exist_ok=True)
|
||||
(build_dir / "index.txt").write_text("hello")
|
||||
@@ -78,7 +33,9 @@ async def test_extensions_builder_api_build_preview_and_cleanup(
|
||||
original_data_folder = settings.lnbits_data_folder
|
||||
build_mock = mocker.patch(
|
||||
"lnbits.core.views.extensions_builder_api.build_extension_from_data",
|
||||
mocker.AsyncMock(return_value=(_release(ext_id), build_dir)),
|
||||
mocker.AsyncMock(
|
||||
return_value=(make_extension_release(ext_id, "0.1.0"), build_dir)
|
||||
),
|
||||
)
|
||||
clean_mock = mocker.patch(
|
||||
"lnbits.core.views.extensions_builder_api.clean_extension_builder_data"
|
||||
@@ -108,7 +65,7 @@ async def test_extensions_builder_api_deploy_updates_user_extension(
|
||||
tmp_path, settings: Settings, mocker, admin_user
|
||||
):
|
||||
ext_id = f"deploy_{uuid4().hex[:8]}"
|
||||
data = _extension_data(ext_id)
|
||||
data = make_extension_data(ext_id)
|
||||
account = await get_account(admin_user.id)
|
||||
assert account is not None
|
||||
|
||||
@@ -123,7 +80,9 @@ async def test_extensions_builder_api_deploy_updates_user_extension(
|
||||
|
||||
mocker.patch(
|
||||
"lnbits.core.views.extensions_builder_api.build_extension_from_data",
|
||||
mocker.AsyncMock(return_value=(_release(ext_id), build_root)),
|
||||
mocker.AsyncMock(
|
||||
return_value=(make_extension_release(ext_id, "0.1.0"), build_root)
|
||||
),
|
||||
)
|
||||
install_mock = mocker.patch(
|
||||
"lnbits.core.views.extensions_builder_api.install_extension",
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
from uuid import uuid4
|
||||
|
||||
import pytest
|
||||
from bolt11.types import MilliSatoshi
|
||||
from fastapi import HTTPException
|
||||
from lnurl import (
|
||||
LnAddress,
|
||||
@@ -13,7 +12,7 @@ from lnurl import (
|
||||
LnurlResponseException,
|
||||
)
|
||||
from lnurl.models import MessageAction
|
||||
from lnurl.types import CallbackUrl, LightningInvoice, LnurlPayMetadata
|
||||
from lnurl.types import CallbackUrl, LightningInvoice
|
||||
from pydantic import parse_obj_as
|
||||
|
||||
from lnbits.core.models import Account, CreateInvoice
|
||||
@@ -27,6 +26,7 @@ from lnbits.core.views.lnurl_api import (
|
||||
api_payments_pay_lnurl,
|
||||
api_perform_lnurlauth,
|
||||
)
|
||||
from tests.helpers import make_lnurl_pay_response
|
||||
|
||||
TEST_BOLT11 = (
|
||||
"lnbc1pnsu5z3pp57getmdaxhg5kc9yh2a2qsh7cjf4gnccgkw0qenm8vsqv50w7s"
|
||||
@@ -37,20 +37,9 @@ TEST_BOLT11 = (
|
||||
)
|
||||
|
||||
|
||||
def _pay_response() -> LnurlPayResponse:
|
||||
return LnurlPayResponse(
|
||||
callback=parse_obj_as(CallbackUrl, "https://example.com/callback"),
|
||||
minSendable=MilliSatoshi(1_000),
|
||||
maxSendable=MilliSatoshi(10_000),
|
||||
metadata=LnurlPayMetadata(
|
||||
'[["text/plain","Test payment"],["text/identifier","alice@example.com"]]'
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.anyio
|
||||
async def test_lnurl_api_scan_routes_validate_and_forward(mocker):
|
||||
pay_response = _pay_response()
|
||||
pay_response = make_lnurl_pay_response()
|
||||
mocker.patch(
|
||||
"lnbits.core.views.lnurl_api.lnurl_handle",
|
||||
mocker.AsyncMock(return_value=pay_response),
|
||||
@@ -92,7 +81,7 @@ async def test_lnurl_api_auth_and_pay_flow(mocker):
|
||||
)
|
||||
wallet = user.wallets[0]
|
||||
wallet_info = WalletTypeInfo(key_type=KeyType.admin, wallet=wallet)
|
||||
pay_response = _pay_response()
|
||||
pay_response = make_lnurl_pay_response()
|
||||
payment = await create_wallet_invoice(
|
||||
wallet.id, CreateInvoice(out=False, amount=21, memo="lnurl")
|
||||
)
|
||||
|
||||
@@ -33,30 +33,6 @@ ZERO_AMOUNT_INVOICE = (
|
||||
)
|
||||
|
||||
|
||||
async def _create_payment(
|
||||
wallet_id: str,
|
||||
*,
|
||||
amount_msat: int,
|
||||
status: PaymentState = PaymentState.SUCCESS,
|
||||
payment_hash: str | None = None,
|
||||
tag: str | None = None,
|
||||
) -> str:
|
||||
checking_id = f"checking_{uuid4().hex[:8]}"
|
||||
await create_payment(
|
||||
checking_id=checking_id,
|
||||
data=CreatePayment(
|
||||
wallet_id=wallet_id,
|
||||
payment_hash=payment_hash or uuid4().hex,
|
||||
bolt11=f"bolt11_{checking_id}",
|
||||
amount_msat=amount_msat,
|
||||
memo=f"payment_{checking_id}",
|
||||
extra={"tag": tag} if tag else {},
|
||||
),
|
||||
status=status,
|
||||
)
|
||||
return checking_id
|
||||
|
||||
|
||||
@pytest.mark.anyio
|
||||
async def test_payment_api_stats_and_all_paginated(admin_user):
|
||||
first_user = await create_user_account(
|
||||
@@ -185,3 +161,27 @@ async def test_payment_api_fee_reserve_and_hold_invoice_actions(mocker):
|
||||
)
|
||||
assert cancelled.failed is True
|
||||
cancel_mock.assert_awaited_once()
|
||||
|
||||
|
||||
async def _create_payment(
|
||||
wallet_id: str,
|
||||
*,
|
||||
amount_msat: int,
|
||||
status: PaymentState = PaymentState.SUCCESS,
|
||||
payment_hash: str | None = None,
|
||||
tag: str | None = None,
|
||||
) -> str:
|
||||
checking_id = f"checking_{uuid4().hex[:8]}"
|
||||
await create_payment(
|
||||
checking_id=checking_id,
|
||||
data=CreatePayment(
|
||||
wallet_id=wallet_id,
|
||||
payment_hash=payment_hash or uuid4().hex,
|
||||
bolt11=f"bolt11_{checking_id}",
|
||||
amount_msat=amount_msat,
|
||||
memo=f"payment_{checking_id}",
|
||||
extra={"tag": tag} if tag else {},
|
||||
),
|
||||
status=status,
|
||||
)
|
||||
return checking_id
|
||||
|
||||
@@ -8,10 +8,6 @@ from lnbits.core.models.users import Account
|
||||
from lnbits.core.services.users import create_user_account
|
||||
|
||||
|
||||
def _admin_headers(adminkey: str) -> dict[str, str]:
|
||||
return {"X-Api-Key": adminkey, "Content-type": "application/json"}
|
||||
|
||||
|
||||
@pytest.mark.anyio
|
||||
async def test_wallet_api_share_invite_reject_accept_and_delete(
|
||||
http_client: AsyncClient,
|
||||
@@ -188,3 +184,7 @@ async def test_wallet_api_shared_wallet_requires_source_id(http_client: AsyncCli
|
||||
assert (
|
||||
response.json()["detail"] == "Shared wallet ID is required for shared wallets."
|
||||
)
|
||||
|
||||
|
||||
def _admin_headers(adminkey: str) -> dict[str, str]:
|
||||
return {"X-Api-Key": adminkey, "Content-type": "application/json"}
|
||||
|
||||
Reference in New Issue
Block a user