"""Model-level tests: defaults, constraints, JSON roundtrip, linkage.""" import uuid import pytest from sqlalchemy.exc import IntegrityError from sqlmodel import select from app.models import ApprovalTask, FlowDefinition, FlowRun, FlowVersion def test_flow_definition_defaults(session): from datetime import UTC, datetime before = datetime.now(UTC).replace(tzinfo=None) d = FlowDefinition(name="bauvorhaben") session.add(d) session.commit() session.refresh(d) assert d.id is not None assert d.status == "active" assert d.continuation_flow_id is None assert d.created_at is not None # Timestamps are written as UTC. SQLite does not round-trip tzinfo, so # after a refresh the value is calendar-time UTC without tzinfo. assert d.created_at.tzinfo is None assert abs((d.created_at - before).total_seconds()) < 60 def test_flow_definition_name_unique(session): session.add(FlowDefinition(name="doppelt")) session.commit() session.add(FlowDefinition(name="doppelt")) with pytest.raises(IntegrityError): session.commit() session.rollback() def test_flow_version_unique_per_flow(session): d = FlowDefinition(name="v-flow") session.add(d) session.commit() session.add(FlowVersion(flow_id=d.id, version_no=1, author="a")) session.commit() session.add(FlowVersion(flow_id=d.id, version_no=1, author="b")) with pytest.raises(IntegrityError): session.commit() session.rollback() session.add(FlowVersion(flow_id=d.id, version_no=2, author="b")) session.commit() def test_flow_version_json_roundtrip(session): payload = {"data": {"nodes": [{"id": "n1"}], "edges": []}, "name": "x"} d = FlowDefinition(name="json-flow") session.add(d) session.commit() v = FlowVersion(flow_id=d.id, version_no=1, langflow_json=payload) session.add(v) session.commit() session.refresh(v) assert v.langflow_json == payload assert v.deployed_at is None assert v.lfx_flow_id is None def test_run_and_task_linkage_with_tenant_default(session): d = FlowDefinition(name="linked") session.add(d) session.commit() v = FlowVersion(flow_id=d.id, version_no=1) session.add(v) session.commit() run = FlowRun(version_id=v.id, input={"a": 1}) session.add(run) session.commit() task = ApprovalTask(run_id=run.id, version_id=v.id, title="bitte pruefen") session.add(task) session.commit() assert run.tenant_id == "default" assert run.status == "running" assert task.tenant_id == "default" assert task.status == "open" runs = session.exec(select(FlowRun).where(FlowRun.version_id == v.id)).all() assert len(runs) == 1 tasks = session.exec(select(ApprovalTask).where(ApprovalTask.run_id == run.id)).all() assert len(tasks) == 1 assert tasks[0].payload == {} def test_create_version_populates_input_schema(session): from app.flows import store from app.flows.schemas import FlowVersionCreate d = FlowDefinition(name="cached") session.add(d) session.commit() doc = { "name": "cached", "data": { "nodes": [ { "id": "n1", "data": { "type": "ChatInput", "node": {"display_name": "Chat", "template": {}}, }, } ], "edges": [], }, } version = store.create_version(session, d.id, FlowVersionCreate(langflow_json=doc)) assert version.input_schema["fallback"] == "textarea" def test_input_schema_null_rejected(session): from sqlalchemy import text from sqlalchemy.exc import IntegrityError d = FlowDefinition(name="nonnull") session.add(d) session.commit() with pytest.raises(IntegrityError): session.execute( text( "INSERT INTO flow_versions (id, flow_id, version_no, langflow_json," " author, input_schema) VALUES (:id, :flow_id, 1, :doc, :author, NULL)" ), {"id": str(uuid.uuid4()), "flow_id": str(d.id), "doc": "{}", "author": "t"}, ) session.commit() session.rollback()