mirror of
https://github.com/langgenius/dify.git
synced 2026-07-30 16:59:35 +08:00
test: use SQLite sessions in controllers console app (#39095)
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
This commit is contained in:
parent
3453fdce44
commit
9e8733413a
@ -10,6 +10,8 @@ from unittest.mock import Mock
|
||||
import pytest
|
||||
from flask import Flask
|
||||
from pydantic import ValidationError
|
||||
from sqlalchemy import Engine
|
||||
from sqlalchemy.orm import Session
|
||||
from werkzeug.exceptions import HTTPException, NotFound
|
||||
|
||||
from controllers.common.errors import InvalidArgumentError
|
||||
@ -331,45 +333,34 @@ def test_restore_published_workflow_to_draft_returns_400_for_invalid_structure(
|
||||
|
||||
|
||||
def test_get_published_workflows_serializes_items_before_session_closes(
|
||||
app: Flask, monkeypatch: pytest.MonkeyPatch
|
||||
app: Flask, monkeypatch: pytest.MonkeyPatch, sqlite_engine: Engine
|
||||
) -> None:
|
||||
api = workflow_module.PublishedAllWorkflowApi()
|
||||
handler = inspect.unwrap(api.get)
|
||||
|
||||
session_state = {"open": False}
|
||||
|
||||
class _SessionContext:
|
||||
def __enter__(self):
|
||||
session_state["open"] = True
|
||||
return object()
|
||||
|
||||
def __exit__(self, exc_type, exc, tb):
|
||||
session_state["open"] = False
|
||||
return False
|
||||
|
||||
class _SessionMaker:
|
||||
def begin(self):
|
||||
return _SessionContext()
|
||||
|
||||
base_workflow = _make_workflow()
|
||||
|
||||
class _Workflow:
|
||||
def __init__(self, session: Session) -> None:
|
||||
self._session = session
|
||||
|
||||
def __getattr__(self, name):
|
||||
return getattr(base_workflow, name)
|
||||
|
||||
@property
|
||||
def id(self):
|
||||
assert session_state["open"] is True
|
||||
assert self._session.in_transaction()
|
||||
return "w1"
|
||||
|
||||
monkeypatch.setattr(workflow_module, "db", SimpleNamespace(engine=object()))
|
||||
monkeypatch.setattr(workflow_module, "sessionmaker", lambda *_args, **_kwargs: _SessionMaker())
|
||||
def get_all_published_workflow(*, session: Session, **_kwargs):
|
||||
assert isinstance(session, Session)
|
||||
return [_Workflow(session)], False
|
||||
|
||||
monkeypatch.setattr(workflow_module, "db", SimpleNamespace(engine=sqlite_engine))
|
||||
monkeypatch.setattr(
|
||||
workflow_module,
|
||||
"WorkflowService",
|
||||
lambda: SimpleNamespace(
|
||||
get_all_published_workflow=lambda **_kwargs: ([_Workflow()], False),
|
||||
),
|
||||
lambda: SimpleNamespace(get_all_published_workflow=get_all_published_workflow),
|
||||
)
|
||||
|
||||
with app.test_request_context(
|
||||
|
||||
@ -1,19 +1,68 @@
|
||||
"""Console workflow pause-detail tests backed by persisted workflow execution state."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import inspect
|
||||
from dataclasses import dataclass
|
||||
from datetime import datetime
|
||||
from types import SimpleNamespace
|
||||
from unittest.mock import Mock
|
||||
from uuid import uuid4
|
||||
|
||||
import pytest
|
||||
from flask import Flask
|
||||
from sqlalchemy.engine import Engine
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from controllers.common.errors import NotFoundError
|
||||
from controllers.console.app import workflow_run as workflow_run_module
|
||||
from core.workflow.nodes.human_input.entities import ParagraphInputConfig, UserActionConfig
|
||||
from core.workflow.nodes.human_input.pause_reason import HumanInputRequired
|
||||
from graphon.enums import WorkflowExecutionStatus
|
||||
from models.workflow import WorkflowRun
|
||||
from models.enums import CreatorUserRole, WorkflowRunTriggeredFrom
|
||||
from models.workflow import WorkflowPause, WorkflowRun, WorkflowType
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class _Database:
|
||||
engine: Engine
|
||||
session: Session
|
||||
|
||||
|
||||
def _persist_run(
|
||||
session: Session,
|
||||
*,
|
||||
run_id: str,
|
||||
tenant_id: str,
|
||||
status: WorkflowExecutionStatus,
|
||||
paused: bool = False,
|
||||
) -> WorkflowRun:
|
||||
workflow_id = str(uuid4())
|
||||
workflow_run = WorkflowRun(
|
||||
id=run_id,
|
||||
tenant_id=tenant_id,
|
||||
app_id=str(uuid4()),
|
||||
workflow_id=workflow_id,
|
||||
type=WorkflowType.WORKFLOW,
|
||||
triggered_from=WorkflowRunTriggeredFrom.DEBUGGING,
|
||||
version="draft",
|
||||
graph="{}",
|
||||
inputs="{}",
|
||||
status=status,
|
||||
created_by_role=CreatorUserRole.ACCOUNT,
|
||||
created_by=str(uuid4()),
|
||||
created_at=datetime(2024, 1, 1, 12, 0, 0),
|
||||
)
|
||||
session.add(workflow_run)
|
||||
if paused:
|
||||
session.add(
|
||||
WorkflowPause(
|
||||
workflow_id=workflow_id,
|
||||
workflow_run_id=run_id,
|
||||
state_object_key="workflow-pauses/state.json",
|
||||
)
|
||||
)
|
||||
session.commit()
|
||||
return workflow_run
|
||||
|
||||
|
||||
class _PauseEntity:
|
||||
@ -25,15 +74,25 @@ class _PauseEntity:
|
||||
return self._reasons
|
||||
|
||||
|
||||
def test_pause_details_returns_backstage_input_url(app: Flask, monkeypatch: pytest.MonkeyPatch) -> None:
|
||||
def test_pause_details_returns_backstage_input_url(
|
||||
app: Flask, monkeypatch: pytest.MonkeyPatch, sqlite_session: Session
|
||||
) -> None:
|
||||
monkeypatch.setattr(workflow_run_module.dify_config, "APP_WEB_URL", "https://web.example.com")
|
||||
|
||||
workflow_run = Mock(spec=WorkflowRun)
|
||||
workflow_run.tenant_id = "tenant-123"
|
||||
workflow_run.status = WorkflowExecutionStatus.PAUSED
|
||||
workflow_run.created_at = datetime(2024, 1, 1, 12, 0, 0)
|
||||
fake_db = SimpleNamespace(engine=Mock(), session=SimpleNamespace(get=lambda *_: workflow_run))
|
||||
monkeypatch.setattr(workflow_run_module, "db", fake_db)
|
||||
tenant_id = str(uuid4())
|
||||
run_id = str(uuid4())
|
||||
_persist_run(
|
||||
sqlite_session,
|
||||
run_id=run_id,
|
||||
tenant_id=tenant_id,
|
||||
status=WorkflowExecutionStatus.PAUSED,
|
||||
paused=True,
|
||||
)
|
||||
monkeypatch.setattr(
|
||||
workflow_run_module,
|
||||
"db",
|
||||
_Database(engine=sqlite_session.get_bind(), session=sqlite_session),
|
||||
)
|
||||
|
||||
reason = HumanInputRequired(
|
||||
form_id="form-1",
|
||||
@ -58,12 +117,12 @@ def test_pause_details_returns_backstage_input_url(app: Flask, monkeypatch: pyte
|
||||
lambda _form_ids: {"form-1": "backstage-token"},
|
||||
)
|
||||
|
||||
with app.test_request_context("/console/api/workflow/run-1/pause-details", method="GET"):
|
||||
with app.test_request_context(f"/console/api/workflow/{run_id}/pause-details", method="GET"):
|
||||
handler = inspect.unwrap(workflow_run_module.ConsoleWorkflowPauseDetailsApi.get)
|
||||
response, status = handler(
|
||||
workflow_run_module.ConsoleWorkflowPauseDetailsApi(),
|
||||
"tenant-123",
|
||||
workflow_run_id="run-1",
|
||||
tenant_id,
|
||||
workflow_run_id=run_id,
|
||||
)
|
||||
|
||||
assert status == 200
|
||||
@ -77,39 +136,56 @@ def test_pause_details_returns_backstage_input_url(app: Flask, monkeypatch: pyte
|
||||
assert "pending_human_inputs" not in response
|
||||
|
||||
|
||||
def test_pause_details_tenant_isolation(app: Flask, monkeypatch: pytest.MonkeyPatch) -> None:
|
||||
def test_pause_details_tenant_isolation(app: Flask, monkeypatch: pytest.MonkeyPatch, sqlite_session: Session) -> None:
|
||||
monkeypatch.setattr(workflow_run_module.dify_config, "APP_WEB_URL", "https://web.example.com")
|
||||
|
||||
workflow_run = Mock(spec=WorkflowRun)
|
||||
workflow_run.tenant_id = "tenant-456"
|
||||
workflow_run.status = WorkflowExecutionStatus.PAUSED
|
||||
workflow_run.created_at = datetime(2024, 1, 1, 12, 0, 0)
|
||||
fake_db = SimpleNamespace(engine=Mock(), session=SimpleNamespace(get=lambda *_: workflow_run))
|
||||
monkeypatch.setattr(workflow_run_module, "db", fake_db)
|
||||
run_id = str(uuid4())
|
||||
_persist_run(
|
||||
sqlite_session,
|
||||
run_id=run_id,
|
||||
tenant_id=str(uuid4()),
|
||||
status=WorkflowExecutionStatus.PAUSED,
|
||||
paused=True,
|
||||
)
|
||||
monkeypatch.setattr(
|
||||
workflow_run_module,
|
||||
"db",
|
||||
_Database(engine=sqlite_session.get_bind(), session=sqlite_session),
|
||||
)
|
||||
|
||||
handler = inspect.unwrap(workflow_run_module.ConsoleWorkflowPauseDetailsApi.get)
|
||||
with app.test_request_context("/console/api/workflow/run-1/pause-details", method="GET"):
|
||||
with app.test_request_context(f"/console/api/workflow/{run_id}/pause-details", method="GET"):
|
||||
with pytest.raises(NotFoundError):
|
||||
handler(
|
||||
workflow_run_module.ConsoleWorkflowPauseDetailsApi(),
|
||||
"tenant-123",
|
||||
workflow_run_id="run-1",
|
||||
str(uuid4()),
|
||||
workflow_run_id=run_id,
|
||||
)
|
||||
|
||||
|
||||
def test_pause_details_returns_empty_response_for_non_paused_run(app: Flask, monkeypatch: pytest.MonkeyPatch) -> None:
|
||||
workflow_run = Mock(spec=WorkflowRun)
|
||||
workflow_run.tenant_id = "tenant-123"
|
||||
workflow_run.status = WorkflowExecutionStatus.RUNNING
|
||||
fake_db = SimpleNamespace(engine=Mock(), session=SimpleNamespace(get=lambda *_: workflow_run))
|
||||
monkeypatch.setattr(workflow_run_module, "db", fake_db)
|
||||
def test_pause_details_returns_empty_response_for_non_paused_run(
|
||||
app: Flask, monkeypatch: pytest.MonkeyPatch, sqlite_session: Session
|
||||
) -> None:
|
||||
tenant_id = str(uuid4())
|
||||
run_id = str(uuid4())
|
||||
_persist_run(
|
||||
sqlite_session,
|
||||
run_id=run_id,
|
||||
tenant_id=tenant_id,
|
||||
status=WorkflowExecutionStatus.RUNNING,
|
||||
)
|
||||
monkeypatch.setattr(
|
||||
workflow_run_module,
|
||||
"db",
|
||||
_Database(engine=sqlite_session.get_bind(), session=sqlite_session),
|
||||
)
|
||||
|
||||
with app.test_request_context("/console/api/workflow/run-1/pause-details", method="GET"):
|
||||
with app.test_request_context(f"/console/api/workflow/{run_id}/pause-details", method="GET"):
|
||||
handler = inspect.unwrap(workflow_run_module.ConsoleWorkflowPauseDetailsApi.get)
|
||||
response, status = handler(
|
||||
workflow_run_module.ConsoleWorkflowPauseDetailsApi(),
|
||||
"tenant-123",
|
||||
workflow_run_id="run-1",
|
||||
tenant_id,
|
||||
workflow_run_id=run_id,
|
||||
)
|
||||
|
||||
assert status == 200
|
||||
|
||||
Loading…
Reference in New Issue
Block a user