Files
lnbits/tests/wasm_ext/conftest.py
T
2026-07-07 18:32:54 +03:00

150 lines
4.3 KiB
Python

from __future__ import annotations
import os
import shutil
import socket
import subprocess
import sys
import time
from collections.abc import Iterator
from pathlib import Path
from typing import Any
import httpx
import pytest
from tests.wasm_ext.helpers import EXTENSION_ID, SERVER_HOST, LiveLNbitsServer
REPO_ROOT = Path(__file__).resolve().parents[2]
@pytest.fixture(scope="session")
def browser_name() -> str:
return "chromium"
@pytest.fixture(scope="session")
def lnbits_server(
tmp_path_factory: pytest.TempPathFactory,
) -> Iterator[LiveLNbitsServer]:
run_root = tmp_path_factory.mktemp("wasm_ext_e2e")
data_dir = run_root / "data"
extensions_root = run_root / "extensions-root"
extension_target = extensions_root / "extensions" / EXTENSION_ID
fixture_extension = REPO_ROOT / "tests" / "fixtures" / EXTENSION_ID
shutil.copytree(fixture_extension, extension_target)
port = _free_tcp_port()
base_url = f"http://{SERVER_HOST}:{port}"
env = {
**os.environ,
"AUTH_HTTPS_ONLY": "false",
"DEBUG": "true",
"HOST": SERVER_HOST,
"LNBITS_ADMIN_UI": "true",
"LNBITS_BACKEND_WALLET_CLASS": "FakeWallet",
"LNBITS_DATA_FOLDER": str(data_dir),
"LNBITS_EXTENSIONS_DEACTIVATE_ALL": "false",
"LNBITS_EXTENSIONS_PATH": str(extensions_root),
"LNBITS_PATH": str(REPO_ROOT),
"PORT": str(port),
"PYTHONUNBUFFERED": "1",
}
process = subprocess.Popen( # noqa: S603
[
sys.executable,
"-m",
"uvicorn",
"lnbits.__main__:app",
"--host",
SERVER_HOST,
"--port",
str(port),
"--loop",
"asyncio",
"--log-level",
"warning",
],
cwd=REPO_ROOT,
env=env,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
text=True,
)
try:
_wait_for_first_install_page(process, base_url)
auth_cookies = _complete_first_install(base_url)
yield LiveLNbitsServer(base_url=base_url, auth_cookies=auth_cookies)
finally:
process.terminate()
try:
process.wait(timeout=10)
except subprocess.TimeoutExpired:
process.kill()
process.wait(timeout=10)
@pytest.fixture
def authenticated_page(page: Any, lnbits_server: LiveLNbitsServer) -> Any:
page.context.add_cookies(lnbits_server.auth_cookies)
return page
def _free_tcp_port() -> int:
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
sock.bind((SERVER_HOST, 0))
return int(sock.getsockname()[1])
def _wait_for_first_install_page(
process: subprocess.Popen[str],
base_url: str,
) -> None:
deadline = time.monotonic() + 60
last_error: Exception | None = None
with httpx.Client(follow_redirects=False, timeout=2) as client:
while time.monotonic() < deadline:
if process.poll() is not None:
output = process.stdout.read() if process.stdout else ""
raise RuntimeError(f"LNbits exited before startup:\n{output}")
try:
response = client.get(f"{base_url}/first_install")
if response.status_code == 200:
return
except httpx.HTTPError as exc:
last_error = exc
time.sleep(0.25)
output = process.stdout.read() if process.stdout else ""
raise TimeoutError(f"LNbits did not start: {last_error}\n{output}")
def _complete_first_install(base_url: str) -> list[dict[str, Any]]:
with httpx.Client(base_url=base_url, follow_redirects=False, timeout=10) as client:
response = client.put(
"/api/v1/auth/first_install",
json={
"username": "wasmtest-admin",
"password": "secret1234",
"password_repeat": "secret1234",
},
)
response.raise_for_status()
enable_response = client.put(f"/api/v1/extension/{EXTENSION_ID}/enable")
enable_response.raise_for_status()
return [
{
"name": cookie.name,
"value": cookie.value,
"url": base_url,
"secure": cookie.secure,
"sameSite": "Lax",
}
for cookie in client.cookies.jar
]