mirror of
https://github.com/langgenius/dify.git
synced 2026-07-21 18:58:35 +08:00
test: use SQLite sessions in services workflow (#39116)
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
This commit is contained in:
parent
97e6a14c13
commit
d333aa31ea
@ -1,9 +1,11 @@
|
||||
"""Tests for human-input delivery with a persisted draft workflow."""
|
||||
|
||||
import json
|
||||
import uuid
|
||||
from types import SimpleNamespace
|
||||
from unittest.mock import MagicMock
|
||||
|
||||
import pytest
|
||||
from sqlalchemy.orm import sessionmaker
|
||||
from sqlalchemy.orm import Session, sessionmaker
|
||||
|
||||
from core.workflow.human_input_adapter import (
|
||||
EmailDeliveryConfig,
|
||||
@ -14,12 +16,42 @@ from core.workflow.human_input_adapter import (
|
||||
)
|
||||
from core.workflow.nodes.human_input.entities import HumanInputNodeData
|
||||
from graphon.enums import BuiltinNodeTypes
|
||||
from models import Account
|
||||
from models.enums import AppStatus
|
||||
from models.model import App, AppMode
|
||||
from models.workflow import Workflow, WorkflowType
|
||||
from services import workflow_service as workflow_service_module
|
||||
from services.workflow_service import WorkflowService
|
||||
|
||||
TENANT_ID = "11111111-1111-1111-1111-111111111111"
|
||||
APP_ID = "22222222-2222-2222-2222-222222222222"
|
||||
ACCOUNT_ID = "33333333-3333-3333-3333-333333333333"
|
||||
|
||||
def _make_service() -> WorkflowService:
|
||||
return WorkflowService(session_maker=sessionmaker())
|
||||
|
||||
def _make_service(sqlite_session: Session) -> WorkflowService:
|
||||
return WorkflowService(
|
||||
session_maker=sessionmaker(bind=sqlite_session.get_bind(), expire_on_commit=False),
|
||||
)
|
||||
|
||||
|
||||
def _app() -> App:
|
||||
return App(
|
||||
id=APP_ID,
|
||||
tenant_id=TENANT_ID,
|
||||
name="Test App",
|
||||
description="",
|
||||
mode=AppMode.WORKFLOW,
|
||||
status=AppStatus.NORMAL,
|
||||
enable_site=False,
|
||||
enable_api=False,
|
||||
max_active_requests=None,
|
||||
)
|
||||
|
||||
|
||||
def _account() -> Account:
|
||||
account = Account(name="Test User", email="test@example.com")
|
||||
account.id = ACCOUNT_ID
|
||||
return account
|
||||
|
||||
|
||||
def _build_node_config(delivery_methods: list[EmailDeliveryMethod]) -> dict[str, object]:
|
||||
@ -36,6 +68,37 @@ def _build_node_config(delivery_methods: list[EmailDeliveryMethod]) -> dict[str,
|
||||
}
|
||||
|
||||
|
||||
def _persist_workflow(sqlite_session: Session, delivery_methods: list[EmailDeliveryMethod]) -> None:
|
||||
node_config = _build_node_config(delivery_methods)
|
||||
node_data = node_config["data"]
|
||||
assert isinstance(node_data, HumanInputNodeData)
|
||||
workflow = Workflow.new(
|
||||
tenant_id=TENANT_ID,
|
||||
app_id=APP_ID,
|
||||
type=WorkflowType.WORKFLOW,
|
||||
version=Workflow.VERSION_DRAFT,
|
||||
graph=json.dumps(
|
||||
{
|
||||
"nodes": [
|
||||
{
|
||||
"id": node_config["id"],
|
||||
"data": node_data.model_dump(mode="json"),
|
||||
}
|
||||
],
|
||||
"edges": [],
|
||||
}
|
||||
),
|
||||
features="{}",
|
||||
created_by=ACCOUNT_ID,
|
||||
environment_variables=[],
|
||||
conversation_variables=[],
|
||||
rag_pipeline_variables=[],
|
||||
)
|
||||
sqlite_session.add(workflow)
|
||||
sqlite_session.commit()
|
||||
sqlite_session.expunge_all()
|
||||
|
||||
|
||||
def _make_email_method(enabled: bool = True, debug_mode: bool = False) -> EmailDeliveryMethod:
|
||||
return EmailDeliveryMethod(
|
||||
id=uuid.uuid4(),
|
||||
@ -52,11 +115,11 @@ def _make_email_method(enabled: bool = True, debug_mode: bool = False) -> EmailD
|
||||
)
|
||||
|
||||
|
||||
def test_human_input_delivery_requires_draft_workflow():
|
||||
service = _make_service()
|
||||
service.get_draft_workflow = MagicMock(return_value=None) # type: ignore[method-assign]
|
||||
app_model = SimpleNamespace(tenant_id="tenant-1", id="app-1")
|
||||
account = SimpleNamespace(id="account-1")
|
||||
@pytest.mark.parametrize("sqlite_session", [(Workflow,)], indirect=True)
|
||||
def test_human_input_delivery_requires_draft_workflow(sqlite_session: Session):
|
||||
service = _make_service(sqlite_session)
|
||||
app_model = _app()
|
||||
account = _account()
|
||||
|
||||
with pytest.raises(ValueError, match="Workflow not initialized"):
|
||||
service.test_human_input_delivery(
|
||||
@ -64,17 +127,19 @@ def test_human_input_delivery_requires_draft_workflow():
|
||||
account=account,
|
||||
node_id="node-1",
|
||||
delivery_method_id="delivery-1",
|
||||
session=MagicMock(),
|
||||
session=sqlite_session,
|
||||
)
|
||||
assert sqlite_session.in_transaction()
|
||||
|
||||
|
||||
def test_human_input_delivery_allows_disabled_method(monkeypatch: pytest.MonkeyPatch):
|
||||
service = _make_service()
|
||||
@pytest.mark.parametrize("sqlite_session", [(Workflow,)], indirect=True)
|
||||
def test_human_input_delivery_allows_disabled_method(
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
sqlite_session: Session,
|
||||
):
|
||||
service = _make_service(sqlite_session)
|
||||
delivery_method = _make_email_method(enabled=False)
|
||||
node_config = _build_node_config([delivery_method])
|
||||
workflow = MagicMock()
|
||||
workflow.get_node_config_by_id.return_value = node_config
|
||||
service.get_draft_workflow = MagicMock(return_value=workflow) # type: ignore[method-assign]
|
||||
_persist_workflow(sqlite_session, [delivery_method])
|
||||
service._build_human_input_variable_pool = MagicMock(return_value=MagicMock()) # type: ignore[attr-defined]
|
||||
node_stub = MagicMock()
|
||||
node_stub.render_form_content_before_submission.return_value = "rendered"
|
||||
@ -91,27 +156,29 @@ def test_human_input_delivery_allows_disabled_method(monkeypatch: pytest.MonkeyP
|
||||
MagicMock(return_value=test_service_instance),
|
||||
)
|
||||
|
||||
app_model = SimpleNamespace(tenant_id="tenant-1", id="app-1")
|
||||
account = SimpleNamespace(id="account-1")
|
||||
app_model = _app()
|
||||
account = _account()
|
||||
|
||||
service.test_human_input_delivery(
|
||||
app_model=app_model,
|
||||
account=account,
|
||||
node_id="node-1",
|
||||
delivery_method_id=str(delivery_method.id),
|
||||
session=MagicMock(),
|
||||
session=sqlite_session,
|
||||
)
|
||||
|
||||
test_service_instance.send_test.assert_called_once()
|
||||
assert sqlite_session.in_transaction()
|
||||
|
||||
|
||||
def test_human_input_delivery_dispatches_to_test_service(monkeypatch: pytest.MonkeyPatch):
|
||||
service = _make_service()
|
||||
@pytest.mark.parametrize("sqlite_session", [(Workflow,)], indirect=True)
|
||||
def test_human_input_delivery_dispatches_to_test_service(
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
sqlite_session: Session,
|
||||
):
|
||||
service = _make_service(sqlite_session)
|
||||
delivery_method = _make_email_method(enabled=True)
|
||||
node_config = _build_node_config([delivery_method])
|
||||
workflow = MagicMock()
|
||||
workflow.get_node_config_by_id.return_value = node_config
|
||||
service.get_draft_workflow = MagicMock(return_value=workflow) # type: ignore[method-assign]
|
||||
_persist_workflow(sqlite_session, [delivery_method])
|
||||
service._build_human_input_variable_pool = MagicMock(return_value=MagicMock()) # type: ignore[attr-defined]
|
||||
node_stub = MagicMock()
|
||||
node_stub.render_form_content_before_submission.return_value = "rendered"
|
||||
@ -128,8 +195,8 @@ def test_human_input_delivery_dispatches_to_test_service(monkeypatch: pytest.Mon
|
||||
MagicMock(return_value=test_service_instance),
|
||||
)
|
||||
|
||||
app_model = SimpleNamespace(tenant_id="tenant-1", id="app-1")
|
||||
account = SimpleNamespace(id="account-1")
|
||||
app_model = _app()
|
||||
account = _account()
|
||||
|
||||
service.test_human_input_delivery(
|
||||
app_model=app_model,
|
||||
@ -137,21 +204,23 @@ def test_human_input_delivery_dispatches_to_test_service(monkeypatch: pytest.Mon
|
||||
node_id="node-1",
|
||||
delivery_method_id=str(delivery_method.id),
|
||||
inputs={"#node-1.output#": "value"},
|
||||
session=MagicMock(),
|
||||
session=sqlite_session,
|
||||
)
|
||||
|
||||
pool_args = service._build_human_input_variable_pool.call_args.kwargs
|
||||
assert pool_args["manual_inputs"] == {"#node-1.output#": "value"}
|
||||
test_service_instance.send_test.assert_called_once()
|
||||
assert sqlite_session.in_transaction()
|
||||
|
||||
|
||||
def test_human_input_delivery_debug_mode_overrides_recipients(monkeypatch: pytest.MonkeyPatch):
|
||||
service = _make_service()
|
||||
@pytest.mark.parametrize("sqlite_session", [(Workflow,)], indirect=True)
|
||||
def test_human_input_delivery_debug_mode_overrides_recipients(
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
sqlite_session: Session,
|
||||
):
|
||||
service = _make_service(sqlite_session)
|
||||
delivery_method = _make_email_method(enabled=True, debug_mode=True)
|
||||
node_config = _build_node_config([delivery_method])
|
||||
workflow = MagicMock()
|
||||
workflow.get_node_config_by_id.return_value = node_config
|
||||
service.get_draft_workflow = MagicMock(return_value=workflow) # type: ignore[method-assign]
|
||||
_persist_workflow(sqlite_session, [delivery_method])
|
||||
service._build_human_input_variable_pool = MagicMock(return_value=MagicMock()) # type: ignore[attr-defined]
|
||||
node_stub = MagicMock()
|
||||
node_stub.render_form_content_before_submission.return_value = "rendered"
|
||||
@ -168,15 +237,15 @@ def test_human_input_delivery_debug_mode_overrides_recipients(monkeypatch: pytes
|
||||
MagicMock(return_value=test_service_instance),
|
||||
)
|
||||
|
||||
app_model = SimpleNamespace(tenant_id="tenant-1", id="app-1")
|
||||
account = SimpleNamespace(id="account-1")
|
||||
app_model = _app()
|
||||
account = _account()
|
||||
|
||||
service.test_human_input_delivery(
|
||||
app_model=app_model,
|
||||
account=account,
|
||||
node_id="node-1",
|
||||
delivery_method_id=str(delivery_method.id),
|
||||
session=MagicMock(),
|
||||
session=sqlite_session,
|
||||
)
|
||||
|
||||
test_service_instance.send_test.assert_called_once()
|
||||
@ -188,3 +257,4 @@ def test_human_input_delivery_debug_mode_overrides_recipients(monkeypatch: pytes
|
||||
recipient = sent_method.config.recipients.items[0]
|
||||
assert isinstance(recipient, MemberRecipient)
|
||||
assert recipient.reference_id == account.id
|
||||
assert sqlite_session.in_transaction()
|
||||
|
||||
Loading…
Reference in New Issue
Block a user