test: migrate residual namespace ORM entities to real models (#40633)

This commit is contained in:
Asuka Minato
2026-08-14 08:52:53 +00:00
committed by GitHub
parent 3acc9470d4
commit 9f364339cc
3 changed files with 104 additions and 58 deletions
@@ -10,7 +10,7 @@ from sqlalchemy.orm import Session
import core.rag.datasource.keyword.jieba.jieba as jieba_module
from core.rag.datasource.keyword.jieba.jieba import Jieba, dumps_with_sets, set_orjson_default
from core.rag.models.document import Document
from models.dataset import DatasetKeywordTable, DocumentSegment
from models.dataset import Dataset, DatasetKeywordTable, DocumentSegment
class _DummyLock:
@@ -21,21 +21,26 @@ class _DummyLock:
return False
def _dataset_keyword_table(data_source_type: str = "database", keyword_table_dict: dict[str, Any] | None = None):
return SimpleNamespace(
def _dataset_keyword_table(
data_source_type: str = "database", keyword_table_dict: dict[str, Any] | None = None
) -> DatasetKeywordTable:
keyword_table = DatasetKeywordTable(
dataset_id="dataset-1",
data_source_type=data_source_type,
get_keyword_table_dict=MagicMock(return_value=keyword_table_dict),
keyword_table="",
)
keyword_table.get_keyword_table_dict = MagicMock(return_value=keyword_table_dict)
return keyword_table
def _dataset(dataset_keyword_table=None, keyword_number=None):
return SimpleNamespace(
def _dataset(dataset_keyword_table: DatasetKeywordTable | None = None, keyword_number: int | None = None) -> Dataset:
dataset = Dataset(
id="dataset-1",
tenant_id="tenant-1",
keyword_number=keyword_number,
get_dataset_keyword_table=MagicMock(return_value=dataset_keyword_table),
)
dataset.get_dataset_keyword_table = MagicMock(return_value=dataset_keyword_table)
return dataset
@pytest.fixture
@@ -368,8 +373,12 @@ def test_multi_create_segment_keywords_uses_provided_and_extracted_keywords(
monkeypatch.setattr(keyword, "_get_dataset_keyword_table", MagicMock(return_value={}))
monkeypatch.setattr(keyword, "_save_dataset_keyword_table", MagicMock())
first_segment = SimpleNamespace(index_node_id="node-1", content="first content", keywords=None)
second_segment = SimpleNamespace(index_node_id="node-2", content="second content", keywords=None)
first_segment = _segment(index_node_id="node-1")
first_segment.content = "first content"
first_segment.keywords = None
second_segment = _segment(index_node_id="node-2")
second_segment.content = "second content"
second_segment.keywords = None
keyword.multi_create_segment_keywords(
[
@@ -1,3 +1,4 @@
import json
from collections import UserString
from datetime import datetime
from types import SimpleNamespace
@@ -19,12 +20,27 @@ from graphon.node_events import NodeRunResult
from graphon.nodes import BuiltinNodeTypes
from graphon.runtime import VariablePool
from graphon.variables.variables import StringVariable
from models.workflow import Workflow, WorkflowType
def _build_typed_node_config(node_type: NodeType):
return {"id": "node-id", "data": BaseNodeData(type=node_type)}
def _workflow() -> Workflow:
"""Build a real transient workflow for single-step orchestration tests."""
return Workflow(
id="workflow-id",
tenant_id="tenant-id",
app_id="app-id",
type=WorkflowType.WORKFLOW,
version=Workflow.VERSION_DRAFT,
graph=json.dumps({"nodes": [], "edges": []}),
_features="{}",
created_by="user-id",
)
def _build_minimal_workflow_entry(
monkeypatch: pytest.MonkeyPatch,
*,
@@ -222,11 +238,12 @@ class TestWorkflowEntryRun:
class TestWorkflowEntrySingleStepRun:
@pytest.mark.parametrize("node_type", [BuiltinNodeTypes.LOOP, BuiltinNodeTypes.ITERATION])
def test_rejects_container_nodes(self, node_type):
workflow = SimpleNamespace(
get_node_config_by_id=lambda _node_id: _build_typed_node_config(node_type),
)
workflow = _workflow()
with pytest.raises(ValueError, match="engine-backed debug endpoints"):
with (
patch.object(workflow, "get_node_config_by_id", return_value=_build_typed_node_config(node_type)),
pytest.raises(ValueError, match="engine-backed debug endpoints"),
):
workflow_entry.WorkflowEntry.single_step_run(
workflow=workflow,
node_id="node-id",
@@ -258,8 +275,14 @@ class TestWorkflowEntrySingleStepRun:
selector=["sys", "conversation_id"],
)
]
workflow = _workflow()
node_config = {
"id": "node-id",
"data": BaseNodeData(type=BuiltinNodeTypes.LLM, version="1", memory=object()),
}
with (
patch.object(workflow, "get_node_config_by_id", return_value=node_config),
patch.object(workflow_entry, "DifyGraphInitContext", return_value=sentinel.graph_init_context),
patch.object(
workflow_entry,
@@ -284,17 +307,6 @@ class TestWorkflowEntrySingleStepRun:
return FakeLLMNode()
dify_node_factory.return_value.create_node.side_effect = _create_node
workflow = SimpleNamespace(
tenant_id="tenant-id",
app_id="app-id",
id="workflow-id",
graph_dict={"nodes": [], "edges": []},
get_node_config_by_id=lambda _node_id: {
"id": "node-id",
"data": SimpleNamespace(type=BuiltinNodeTypes.LLM, version="1", memory=object()),
},
)
node, generator = workflow_entry.WorkflowEntry.single_step_run(
workflow=workflow,
node_id="node-id",
@@ -322,7 +334,13 @@ class TestWorkflowEntrySingleStepRun:
def extract_variable_selector_to_variable_mapping(**_kwargs):
raise NotImplementedError
workflow = _workflow()
with (
patch.object(
workflow,
"get_node_config_by_id",
return_value=_build_typed_node_config(BuiltinNodeTypes.START),
),
patch.object(workflow_entry, "DifyGraphInitContext", return_value=sentinel.graph_init_context),
patch.object(workflow_entry, "GraphRuntimeState", return_value=sentinel.graph_runtime_state),
patch.object(workflow_entry, "build_dify_run_context", return_value={"_dify": "context"}),
@@ -342,14 +360,6 @@ class TestWorkflowEntrySingleStepRun:
),
):
dify_node_factory.return_value.create_node.return_value = FakeNode()
workflow = SimpleNamespace(
tenant_id="tenant-id",
app_id="app-id",
id="workflow-id",
graph_dict={"nodes": [], "edges": []},
get_node_config_by_id=lambda _node_id: _build_typed_node_config(BuiltinNodeTypes.START),
)
node, generator = workflow_entry.WorkflowEntry.single_step_run(
workflow=workflow,
node_id="node-id",
@@ -391,7 +401,13 @@ class TestWorkflowEntrySingleStepRun:
def extract_variable_selector_to_variable_mapping(**_kwargs):
return {"question": ["node", "question"]}
workflow = _workflow()
with (
patch.object(
workflow,
"get_node_config_by_id",
return_value=_build_typed_node_config(BuiltinNodeTypes.DATASOURCE),
),
patch.object(workflow_entry, "DifyGraphInitContext", return_value=sentinel.graph_init_context),
patch.object(workflow_entry, "GraphRuntimeState", return_value=sentinel.graph_runtime_state),
patch.object(workflow_entry, "build_dify_run_context", return_value={"_dify": "context"}),
@@ -411,14 +427,6 @@ class TestWorkflowEntrySingleStepRun:
),
):
dify_node_factory.return_value.create_node.return_value = FakeDatasourceNode()
workflow = SimpleNamespace(
tenant_id="tenant-id",
app_id="app-id",
id="workflow-id",
graph_dict={"nodes": [], "edges": []},
get_node_config_by_id=lambda _node_id: _build_typed_node_config(BuiltinNodeTypes.DATASOURCE),
)
node, generator = workflow_entry.WorkflowEntry.single_step_run(
workflow=workflow,
node_id="node-id",
@@ -451,7 +459,13 @@ class TestWorkflowEntrySingleStepRun:
def version():
return "1"
workflow = _workflow()
with (
patch.object(
workflow,
"get_node_config_by_id",
return_value=_build_typed_node_config(BuiltinNodeTypes.START),
),
patch.object(workflow_entry, "DifyGraphInitContext", return_value=sentinel.graph_init_context),
patch.object(workflow_entry, "GraphRuntimeState", return_value=sentinel.graph_runtime_state),
patch.object(workflow_entry, "build_dify_run_context", return_value={"_dify": "context"}),
@@ -468,14 +482,6 @@ class TestWorkflowEntrySingleStepRun:
),
):
dify_node_factory.return_value.create_node.return_value = FakeNode()
workflow = SimpleNamespace(
tenant_id="tenant-id",
app_id="app-id",
id="workflow-id",
graph_dict={"nodes": [], "edges": []},
get_node_config_by_id=lambda _node_id: _build_typed_node_config(BuiltinNodeTypes.START),
)
with pytest.raises(WorkflowNodeRunFailedError):
workflow_entry.WorkflowEntry.single_step_run(
workflow=workflow,
@@ -9,7 +9,6 @@ from __future__ import annotations
import json
from collections.abc import Sequence
from datetime import UTC, datetime
from types import SimpleNamespace
from typing import Any, Protocol
from unittest.mock import MagicMock, patch
@@ -17,13 +16,26 @@ import pytest
from sqlalchemy.orm import Session
from core.workflow.file_reference import build_file_reference
from core.workflow.nodes.agent_v2.binding_resolver import WorkflowAgentBindingBundle
from graphon.enums import WorkflowExecutionStatus, WorkflowNodeExecutionStatus
from models.agent import (
Agent,
AgentConfigSnapshot,
AgentScope,
AgentSource,
AgentStatus,
WorkflowAgentBindingType,
WorkflowAgentNodeBinding,
)
from models.agent_config_entities import (
AgentSoulConfig,
DeclaredArrayItem,
DeclaredOutputConfig,
DeclaredOutputType,
WorkflowNodeJobConfig,
)
from models.enums import CreatorUserRole, WorkflowRunTriggeredFrom
from models.model import App
from models.workflow import (
WorkflowNodeExecutionModel,
WorkflowNodeExecutionTriggeredFrom,
@@ -43,8 +55,8 @@ from services.workflow.node_output_inspector_service import (
# ──────────────────────────────────────────────────────────────────────────────
def _app_model(*, tenant_id: str = "tenant-1", app_id: str = "app-1"):
return SimpleNamespace(tenant_id=tenant_id, id=app_id)
def _app_model(*, tenant_id: str = "tenant-1", app_id: str = "app-1") -> App:
return App(id=app_id, tenant_id=tenant_id)
def _workflow_run(
@@ -168,16 +180,35 @@ def session_for(sqlite_session: Session) -> SessionFor:
def _stub_binding_resolver(*, declared_outputs: list[DeclaredOutputConfig]):
"""Build a fake ``WorkflowAgentBindingResolver`` whose ``.resolve`` returns
a binding with ``node_job_config_dict.declared_outputs``."""
binding = SimpleNamespace(
binding = WorkflowAgentNodeBinding(
id="binding-1",
node_job_config_dict={
"workflow_prompt": "stub",
"declared_outputs": [o.model_dump() for o in declared_outputs],
},
tenant_id="tenant-1",
app_id="app-1",
workflow_id="workflow-1",
workflow_version="draft",
node_id="agent-node-1",
binding_type=WorkflowAgentBindingType.INLINE_AGENT,
agent_id="agent-1",
current_snapshot_id="snapshot-1",
node_job_config=WorkflowNodeJobConfig(workflow_prompt="stub", declared_outputs=declared_outputs),
)
agent = Agent(
id="agent-1",
tenant_id="tenant-1",
name="Agent",
scope=AgentScope.WORKFLOW_ONLY,
source=AgentSource.WORKFLOW,
status=AgentStatus.ACTIVE,
)
snapshot = AgentConfigSnapshot(
id="snapshot-1",
tenant_id="tenant-1",
agent_id="agent-1",
version=1,
config_snapshot=AgentSoulConfig(),
)
bundle = SimpleNamespace(binding=binding, agent=None, snapshot=None)
resolver = MagicMock()
resolver.resolve.return_value = bundle
resolver.resolve.return_value = WorkflowAgentBindingBundle(binding=binding, agent=agent, snapshot=snapshot)
return resolver