fix: typer exit codes, JWT 7d expiry, shared test fixtures, AdminTab query, mantine 9.6.3

This commit is contained in:
Jonas Miederer 2026-09-30 22:27:58 +02:00
parent 03af41e837
commit 696db34c90
16 changed files with 210 additions and 251 deletions

View file

@ -12,35 +12,9 @@ from .conftest import load_flow_fixture
CALLBACK_HEADERS = {"X-Callback-Token": "test-callback-token"}
def load_fixture(name: str) -> dict:
"""Alias of the shared conftest helper (kept for call-site stability)."""
return load_flow_fixture(name)
async def _create_flow(client, name="regeltest"):
response = await client.post("/api/flows", json={"name": name, "description": "test flow"})
assert response.status_code == 201, response.text
return response.json()
async def _create_version(client, flow_id, fixture="simple_rule.json"):
response = await client.post(
f"/api/flows/{flow_id}/versions",
json={"langflow_json": load_fixture(fixture), "author": "test"},
)
assert response.status_code == 201, response.text
return response.json()
async def _deploy(client, flow_id, version_no=1):
response = await client.post(f"/api/flows/{flow_id}/versions/{version_no}/deploy")
assert response.status_code == 200, response.text
return response.json()
async def test_flow_crud(client, login):
async def test_flow_crud(client, login, flow_helpers):
await login()
created = await _create_flow(client, "crud-flow")
created = await flow_helpers["create_flow"]("crud-flow")
assert created["status"] == "active"
response = await client.get(f"/api/flows/{created['id']}")
@ -98,10 +72,12 @@ LOGIN_GATED_PATHS = [
@pytest.mark.parametrize(("method", "path", "body"), LOGIN_GATED_PATHS)
async def test_runs_and_reads_require_login(client, login, anon_client, method, path, body):
async def test_runs_and_reads_require_login(
client, login, anon_client, flow_helpers, method, path, body
):
"""Run, run reads and approval reads are login-gated (parametrized)."""
await login()
flow = await _create_flow(client, "gated")
flow = await flow_helpers["create_flow"]("gated")
target = path.format(flow_id=flow["id"], run_id=uuid4(), task_id=uuid4())
async for anon in anon_client():
if method == "POST":
@ -111,13 +87,13 @@ async def test_runs_and_reads_require_login(client, login, anon_client, method,
assert response.status_code == 401, (method, target, response.text)
async def test_version_validation_and_numbering(client, login):
async def test_version_validation_and_numbering(client, login, flow_helpers):
await login()
flow = await _create_flow(client, "versioned")
flow = await flow_helpers["create_flow"]("versioned")
v1 = await _create_version(client, flow["id"])
v1 = await flow_helpers["create_version"](flow["id"])
assert v1["version_no"] == 1
v2 = await _create_version(client, flow["id"])
v2 = await flow_helpers["create_version"](flow["id"])
assert v2["version_no"] == 2
assert v1["deployed_at"] is None
@ -128,7 +104,7 @@ async def test_version_validation_and_numbering(client, login):
response = await client.post(
f"/api/flows/{uuid4()}/versions",
json={"langflow_json": load_fixture("simple_rule.json")},
json={"langflow_json": load_flow_fixture("simple_rule.json")},
)
assert response.status_code == 404
@ -136,11 +112,11 @@ async def test_version_validation_and_numbering(client, login):
assert [v["version_no"] for v in response.json()] == [1, 2]
async def test_deploy_and_run_standard_and_sonderfall(client, lfx_server, login):
async def test_deploy_and_run_standard_and_sonderfall(client, lfx_server, login, flow_helpers):
await login()
flow = await _create_flow(client, "dachsanierung")
await _create_version(client, flow["id"])
deployed = await _deploy(client, flow["id"])
flow = await flow_helpers["create_flow"]("dachsanierung")
await flow_helpers["create_version"](flow["id"])
deployed = await flow_helpers["deploy"](flow["id"])
assert deployed["lfx_flow_id"] == lfx_id_for(UUID(flow["id"]), 1)
assert deployed["deployed_at"] is not None
@ -168,20 +144,20 @@ async def test_deploy_and_run_standard_and_sonderfall(client, lfx_server, login)
assert response.json()["id"] == run["id"]
async def test_run_undeployed_version_fails(client, login):
async def test_run_undeployed_version_fails(client, login, flow_helpers):
await login()
flow = await _create_flow(client, "undeployed")
await _create_version(client, flow["id"])
flow = await flow_helpers["create_flow"]("undeployed")
await flow_helpers["create_version"](flow["id"])
response = await client.post(f"/api/flows/{flow['id']}/run", json={"input": {"betrag": 1}})
assert response.status_code == 422
async def test_run_explicit_version_no(client, lfx_server, login):
async def test_run_explicit_version_no(client, lfx_server, login, flow_helpers):
await login()
flow = await _create_flow(client, "explicit-version")
await _create_version(client, flow["id"])
await _create_version(client, flow["id"])
await _deploy(client, flow["id"], version_no=2)
flow = await flow_helpers["create_flow"]("explicit-version")
await flow_helpers["create_version"](flow["id"])
await flow_helpers["create_version"](flow["id"])
await flow_helpers["deploy"](flow["id"], version_no=2)
response = await client.post(
f"/api/flows/{flow['id']}/run",
json={"input": {"betrag": 1}, "version_no": 2},
@ -190,11 +166,11 @@ async def test_run_explicit_version_no(client, lfx_server, login):
assert response.json()["status"] == "completed"
async def test_run_stream_events(client, lfx_server, login):
async def test_run_stream_events(client, lfx_server, login, flow_helpers):
await login()
flow = await _create_flow(client, "streamed")
await _create_version(client, flow["id"])
await _deploy(client, flow["id"])
flow = await flow_helpers["create_flow"]("streamed")
await flow_helpers["create_version"](flow["id"])
await flow_helpers["deploy"](flow["id"])
events: list[tuple[str, str]] = []
async with client.stream(
@ -225,14 +201,16 @@ async def test_run_stream_events(client, lfx_server, login):
assert response.json()["status"] == "completed"
async def test_approval_handoff_end_to_end(client, lfx_server, live_server, login, monkeypatch):
async def test_approval_handoff_end_to_end(
client, lfx_server, live_server, login, monkeypatch, flow_helpers
):
from app.settings import settings
await login()
monkeypatch.setattr(settings, "callback_base_url", live_server)
flow = await _create_flow(client, "freigabe")
await _create_version(client, flow["id"], fixture="approval_handoff.json")
await _deploy(client, flow["id"])
flow = await flow_helpers["create_flow"]("freigabe")
await flow_helpers["create_version"](flow["id"], fixture="approval_handoff.json")
await flow_helpers["deploy"](flow["id"])
response = await client.post(
f"/api/flows/{flow['id']}/run",
@ -254,15 +232,15 @@ async def test_approval_handoff_end_to_end(client, lfx_server, live_server, logi
async def test_approval_handoff_auto_creates_no_task(
client, lfx_server, live_server, login, monkeypatch
client, lfx_server, live_server, login, monkeypatch, flow_helpers
):
from app.settings import settings
await login()
monkeypatch.setattr(settings, "callback_base_url", live_server)
flow = await _create_flow(client, "freigabe-auto")
await _create_version(client, flow["id"], fixture="approval_handoff.json")
await _deploy(client, flow["id"])
flow = await flow_helpers["create_flow"]("freigabe-auto")
await flow_helpers["create_version"](flow["id"], fixture="approval_handoff.json")
await flow_helpers["deploy"](flow["id"])
response = await client.post(
f"/api/flows/{flow['id']}/run",
@ -276,14 +254,14 @@ async def test_approval_handoff_auto_creates_no_task(
assert response.json() == []
async def test_approval_callback_contract(client, session, login):
async def test_approval_callback_contract(client, session, login, flow_helpers):
from uuid import UUID
from app.flows import store as flow_store
await login()
flow = await _create_flow(client, "callback-target")
version = await _create_version(client, flow["id"])
flow = await flow_helpers["create_flow"]("callback-target")
version = await flow_helpers["create_version"](flow["id"])
version_obj = flow_store.get_version(session, UUID(version["id"]))
run = flow_store.create_run(session, version_obj, input={}, tenant_id="default")
@ -321,15 +299,15 @@ async def test_approval_callback_contract(client, session, login):
assert response.status_code == 404
async def test_approval_callback_token_required(client, session, login):
async def test_approval_callback_token_required(client, session, login, flow_helpers):
"""Forged callbacks without the shared token are rejected (C)."""
from uuid import UUID
from app.flows import store as flow_store
await login()
flow = await _create_flow(client, "callback-gated")
version = await _create_version(client, flow["id"])
flow = await flow_helpers["create_flow"]("callback-gated")
version = await flow_helpers["create_version"](flow["id"])
version_obj = flow_store.get_version(session, UUID(version["id"]))
run = flow_store.create_run(session, version_obj, input={}, tenant_id="default")