Files
dify/api/tests/unit_tests/models/test_dify_builder_models.py
T
Charles YaoandClaude Opus 4.8 7e83264330 refactor: rename Workflow Copilot → Dify Builder
Project rename across api/ + web/: modules, symbols, routes
(/console/api/dify-builder/*), feature flag (DIFY_BUILDER_ENABLED),
Celery queue/tasks, the 7 DB tables (via migration df1b0114de40),
and regenerated contract artifacts. Behavior unchanged; 430 tests green,
ruff clean. Branch renamed feat/copilot-py-backend → dify-builder.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-23 11:18:35 -07:00

191 lines
5.1 KiB
Python

"""Model-level tests for the Dify Builder persistence tables.
Verifies the 7 dify_builder tables against an in-memory SQLite engine: default
values (`id`, `version`, timestamps) populate on flush, and the
`(session_id, seq)` uniqueness on conversation items is a real DB constraint.
"""
from collections.abc import Iterator
import pytest
from sqlalchemy import create_engine
from sqlalchemy.engine import Engine
from sqlalchemy.exc import IntegrityError
from sqlalchemy.orm import Session
from models.base import Base
from models.dify_builder import (
DifyBuilderCheckpoint,
DifyBuilderConversationItem,
DifyBuilderRun,
DifyBuilderSession,
DifyBuilderSessionCommit,
DifyBuilderSnapshot,
DifyBuilderTestInput,
)
TENANT_ID = "11111111-1111-1111-1111-111111111111"
APP_ID = "22222222-2222-2222-2222-222222222222"
ACCOUNT_ID = "33333333-3333-3333-3333-333333333333"
@pytest.fixture
def engine() -> Iterator[Engine]:
engine = create_engine("sqlite://")
Base.metadata.create_all(engine)
try:
yield engine
finally:
engine.dispose()
@pytest.fixture
def session(engine: Engine) -> Iterator[Session]:
with Session(engine) as session:
yield session
def _make_session(**overrides) -> DifyBuilderSession:
kwargs = {
"app_id": APP_ID,
"tenant_id": TENANT_ID,
"owner_account_id": ACCOUNT_ID,
"entry_mode": "chat",
"current_state": "idle",
}
kwargs.update(overrides)
return DifyBuilderSession(**kwargs)
def test_dify_builder_session_defaults_populate_on_flush(session: Session) -> None:
dify_builder_session = _make_session()
session.add(dify_builder_session)
session.flush()
session.refresh(dify_builder_session)
assert dify_builder_session.id
assert dify_builder_session.version == 1
assert dify_builder_session.created_at is not None
assert dify_builder_session.updated_at is not None
def test_conversation_item_duplicate_seq_raises_integrity_error(session: Session) -> None:
dify_builder_session = _make_session()
session.add(dify_builder_session)
session.flush()
session.add_all(
[
DifyBuilderConversationItem(
session_id=dify_builder_session.id,
seq=1,
kind="user_message",
payload={"text": "hello"},
at_version=1,
),
DifyBuilderConversationItem(
session_id=dify_builder_session.id,
seq=2,
kind="agent_message",
payload={"text": "hi"},
at_version=1,
),
]
)
session.flush()
session.add(
DifyBuilderConversationItem(
session_id=dify_builder_session.id,
seq=1,
kind="user_message",
payload={"text": "duplicate"},
at_version=1,
)
)
with pytest.raises(IntegrityError):
session.flush()
def test_session_commit_round_trips_context(session: Session) -> None:
dify_builder_session = _make_session()
session.add(dify_builder_session)
session.flush()
commit = DifyBuilderSessionCommit(
session_id=dify_builder_session.id,
version=1,
state="idle",
context={"diagnosis": None, "staged_repair": []},
actor="system",
)
session.add(commit)
session.flush()
session.refresh(commit)
assert commit.id
assert commit.context == {"diagnosis": None, "staged_repair": []}
assert commit.created_at is not None
def test_snapshot_and_checkpoint_round_trip(session: Session) -> None:
dify_builder_session = _make_session()
session.add(dify_builder_session)
session.flush()
snapshot = DifyBuilderSnapshot(
session_id=dify_builder_session.id,
hash="deadbeef",
graph={"nodes": [], "edges": []},
)
session.add(snapshot)
session.flush()
session.refresh(snapshot)
checkpoint = DifyBuilderCheckpoint(
session_id=dify_builder_session.id,
state="verified",
snapshot_id=snapshot.id,
)
session.add(checkpoint)
session.flush()
session.refresh(checkpoint)
assert snapshot.id
assert checkpoint.id
assert checkpoint.snapshot_id == snapshot.id
def test_run_and_test_input_round_trip(session: Session) -> None:
dify_builder_session = _make_session()
session.add(dify_builder_session)
session.flush()
run = DifyBuilderRun(
session_id=dify_builder_session.id,
kind="verify",
dify_run_id="run-123",
status="succeeded",
per_node={"node-1": "ok"},
culprit_node_id=None,
inputs_ref="ref-1",
tokens=42,
elapsed_ms=1000,
immutable=True,
)
test_input = DifyBuilderTestInput(
session_id=dify_builder_session.id,
source="user",
inputs={"query": "hi"},
start_schema_hash="hash-1",
)
session.add_all([run, test_input])
session.flush()
session.refresh(run)
session.refresh(test_input)
assert run.id
assert run.immutable is True
assert test_input.id