refactor(api): migrate service api workflow responses from marshal_with to BaseModel (#35195)

Co-authored-by: ai-hpc <ai-hpc@users.noreply.github.com>
This commit is contained in:
NVIDIAN
2026-04-14 19:50:59 +00:00
committed by GitHub
co-authored by ai-hpc
parent 1c3cba281a
commit b65a5fcd97
2 changed files with 176 additions and 40 deletions
@@ -15,6 +15,7 @@ Focus on:
import sys
import uuid
from datetime import UTC, datetime
from types import SimpleNamespace
from unittest.mock import Mock, patch
@@ -43,6 +44,22 @@ from services.errors.llm import InvokeRateLimitError
from services.workflow_app_service import WorkflowAppService
def _make_mock_workflow_run(run_id: str = "run-1"):
run = Mock()
run.id = run_id
run.workflow_id = "wf-1"
run.status = WorkflowExecutionStatus.SUCCEEDED
run.inputs = {"input": "value"}
run.outputs_dict = {"output": "value"}
run.error = None
run.total_steps = 1
run.total_tokens = 10
run.created_at = datetime(2026, 1, 1, tzinfo=UTC)
run.finished_at = datetime(2026, 1, 1, tzinfo=UTC)
run.elapsed_time = 0.1
return run
class TestWorkflowRunPayload:
"""Test suite for WorkflowRunPayload Pydantic model."""
@@ -359,7 +376,7 @@ class TestWorkflowRunDetailApi:
handler(api, app_model=app_model, workflow_run_id="run")
def test_success(self, monkeypatch: pytest.MonkeyPatch) -> None:
run = SimpleNamespace(id="run")
run = _make_mock_workflow_run(run_id="run")
repo = SimpleNamespace(get_workflow_run_by_id=lambda **_kwargs: run)
workflow_module = sys.modules["controllers.service_api.app.workflow"]
monkeypatch.setattr(workflow_module, "db", SimpleNamespace(engine=object()))
@@ -373,7 +390,10 @@ class TestWorkflowRunDetailApi:
handler = _unwrap(api.get)
app_model = SimpleNamespace(mode=AppMode.WORKFLOW.value, tenant_id="t1", id="a1")
assert handler(api, app_model=app_model, workflow_run_id="run") == run
result = handler(api, app_model=app_model, workflow_run_id="run")
assert result["id"] == "run"
assert result["workflow_id"] == "wf-1"
assert result["status"] == "succeeded"
class TestWorkflowRunApi:
@@ -490,7 +510,7 @@ class TestWorkflowAppLogApi:
monkeypatch.setattr(
WorkflowAppService,
"get_paginate_workflow_app_logs",
lambda *_args, **_kwargs: {"items": [], "total": 0},
lambda *_args, **_kwargs: {"page": 1, "limit": 20, "total": 0, "has_more": False, "data": []},
)
api = WorkflowAppLogApi()
@@ -500,7 +520,7 @@ class TestWorkflowAppLogApi:
with app.test_request_context("/workflows/logs", method="GET"):
response = handler(api, app_model=app_model)
assert response == {"items": [], "total": 0}
assert response == {"page": 1, "limit": 20, "total": 0, "has_more": False, "data": []}
# =============================================================================
@@ -527,9 +547,8 @@ def mock_workflow_app():
class TestWorkflowRunDetailApiGet:
"""Test suite for WorkflowRunDetailApi.get() endpoint.
``get`` is wrapped by ``@validate_app_token`` (preserves ``__wrapped__``)
and ``@service_api_ns.marshal_with``. We call the unwrapped method
directly; ``marshal_with`` is a no-op when calling directly.
``get`` is wrapped by ``@validate_app_token`` (preserves ``__wrapped__``),
and we call the unwrapped method directly in tests.
"""
@patch("controllers.service_api.app.workflow.DifyAPIRepositoryFactory")
@@ -542,9 +561,7 @@ class TestWorkflowRunDetailApiGet:
mock_workflow_app,
):
"""Test successful workflow run detail retrieval."""
mock_run = Mock()
mock_run.id = "run-1"
mock_run.status = "succeeded"
mock_run = _make_mock_workflow_run(run_id="run-1")
mock_repo = Mock()
mock_repo.get_workflow_run_by_id.return_value = mock_run
mock_repo_factory.create_api_workflow_run_repository.return_value = mock_repo
@@ -558,7 +575,8 @@ class TestWorkflowRunDetailApiGet:
api = WorkflowRunDetailApi()
result = _unwrap(api.get)(api, app_model=mock_workflow_app, workflow_run_id=mock_run.id)
assert result == mock_run
assert result["id"] == mock_run.id
assert result["status"] == "succeeded"
@patch("controllers.service_api.app.workflow.db")
def test_get_workflow_run_wrong_app_mode(self, mock_db, app):
@@ -622,8 +640,7 @@ class TestWorkflowTaskStopApiPost:
class TestWorkflowAppLogApiGet:
"""Test suite for WorkflowAppLogApi.get() endpoint.
``get`` is wrapped by ``@validate_app_token`` and
``@service_api_ns.marshal_with``.
``get`` is wrapped by ``@validate_app_token``.
"""
@patch("controllers.service_api.app.workflow.WorkflowAppService")
@@ -637,6 +654,10 @@ class TestWorkflowAppLogApiGet:
):
"""Test successful workflow log retrieval."""
mock_pagination = Mock()
mock_pagination.page = 1
mock_pagination.limit = 20
mock_pagination.total = 0
mock_pagination.has_more = False
mock_pagination.data = []
mock_svc_instance = Mock()
mock_svc_instance.get_paginate_workflow_app_logs.return_value = mock_pagination
@@ -661,4 +682,4 @@ class TestWorkflowAppLogApiGet:
api = WorkflowAppLogApi()
result = _unwrap(api.get)(api, app_model=mock_workflow_app)
assert result == mock_pagination
assert result == {"page": 1, "limit": 20, "total": 0, "has_more": False, "data": []}