kirche-einfach/backend/tests/test_deploy.py
Jonas Miederer 1034206870 feat: Langflow authoring pipeline with tests
- LangflowClient (list/export, x-api-key auth, error mapping)
- import_from_langflow: export -> versioned definition -> LFX deploy
- POST /api/flows/import, GET /api/flows/langflow/available
- scripts/deploy_flow.py CLI
- 25 tests green (Langflow faked via dependency override + respx
  client tests; respx passthrough proven unreliable for LFX traffic)
2026-09-06 23:01:47 +00:00

109 lines
3.7 KiB
Python

"""Step 4 tests: Langflow import pipeline (Langflow faked, LFX real)."""
import json
from pathlib import Path
from uuid import uuid4
FIXTURES = Path(__file__).parent / "fixtures" / "flows"
LANGFLOW_ID = "11111111-2222-4333-8444-555555555555"
def _export_doc(name="importiert"):
fixture = json.loads((FIXTURES / "simple_rule.json").read_text())
return {
"id": LANGFLOW_ID,
"name": name,
"description": "aus Langflow",
"endpoint_name": None,
"data": fixture["data"],
"tags": [],
"webhook": False,
"is_component": False,
}
async def test_import_creates_definition_version_and_deploys(
client, lfx_server, override_langflow
):
override_langflow(_export_doc())
response = await client.post(
"/api/flows/import",
json={"langflow_flow_id": LANGFLOW_ID, "author": "admin"},
)
assert response.status_code == 201, response.text
body = response.json()
assert body["definition"]["name"] == "importiert"
assert body["version"]["version_no"] == 1
assert body["version"]["author"] == "admin"
assert body["version"]["lfx_flow_id"] == body["version"]["id"]
assert body["version"]["deployed_at"] is not None
assert body["version"]["langflow_json"]["data"]["nodes"]
# Imported flow actually runs on LFX.
definition_id = body["definition"]["id"]
response = await client.post(
f"/api/flows/{definition_id}/run", json={"input": {"betrag": 10}}
)
assert response.status_code == 200, response.text
assert response.json()["status"] == "completed"
async def test_import_reuses_definition_and_bumps_version(
client, lfx_server, override_langflow
):
override_langflow(_export_doc())
first = await client.post(
"/api/flows/import", json={"langflow_flow_id": LANGFLOW_ID}
)
second = await client.post(
"/api/flows/import", json={"langflow_flow_id": LANGFLOW_ID}
)
assert first.status_code == 201
assert second.status_code == 201
assert first.json()["definition"]["id"] == second.json()["definition"]["id"]
assert second.json()["version"]["version_no"] == 2
async def test_import_with_explicit_name(client, lfx_server, override_langflow):
override_langflow(_export_doc(name="langflow-name"))
response = await client.post(
"/api/flows/import",
json={"langflow_flow_id": LANGFLOW_ID, "name": "wunschname"},
)
assert response.status_code == 201, response.text
assert response.json()["definition"]["name"] == "wunschname"
async def test_import_without_deploy(client, override_langflow):
override_langflow(_export_doc())
response = await client.post(
"/api/flows/import",
json={"langflow_flow_id": LANGFLOW_ID, "deploy": False},
)
assert response.status_code == 201, response.text
body = response.json()
assert body["version"]["lfx_flow_id"] is None
assert body["version"]["deployed_at"] is None
async def test_import_langflow_not_found(client, override_langflow):
override_langflow(status=404)
response = await client.post(
"/api/flows/import", json={"langflow_flow_id": LANGFLOW_ID}
)
assert response.status_code == 404
async def test_import_langflow_unreachable(client, override_langflow):
override_langflow(status=0)
response = await client.post(
"/api/flows/import", json={"langflow_flow_id": str(uuid4())}
)
assert response.status_code == 503
async def test_list_langflow_flows(client, override_langflow):
override_langflow(_export_doc())
response = await client.get("/api/flows/langflow/available")
assert response.status_code == 200
assert response.json() == [{"id": "fake-1", "name": "fake"}]