chore: add more type in test (#37609)

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
This commit is contained in:
Asuka Minato 2026-06-19 08:07:12 +09:00 committed by GitHub
parent e4500d2b9d
commit bd15b8e6ce
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
51 changed files with 482 additions and 402 deletions

View File

@ -3,6 +3,7 @@
from __future__ import annotations
import types
from inspect import unwrap
from unittest.mock import MagicMock, patch
from uuid import uuid4
@ -13,12 +14,6 @@ from pydantic import ValidationError
import controllers.mcp.mcp as module
def unwrap(func):
while hasattr(func, "__wrapped__"):
func = func.__wrapped__
return func
@pytest.fixture(autouse=True)
def mock_mcp_ns():
fake_ns = types.SimpleNamespace()

View File

@ -1,4 +1,5 @@
import datetime
from inspect import unwrap
from types import SimpleNamespace
from unittest.mock import PropertyMock, patch
@ -8,12 +9,6 @@ from controllers.console import console_ns
from controllers.console.app.mcp_server import AppMCPServerController, AppMCPServerResponse
def unwrap(func):
while hasattr(func, "__wrapped__"):
func = func.__wrapped__
return func
class _ValidatedResponse:
def __init__(self, payload):
self._payload = payload

View File

@ -1,3 +1,4 @@
from inspect import unwrap
from unittest.mock import MagicMock, patch
import pytest
@ -11,12 +12,6 @@ from models import Account
from models.dataset import Pipeline
def unwrap(func):
while hasattr(func, "__wrapped__"):
func = func.__wrapped__
return func
def make_account() -> Account:
account = Account(name="Test User", email="user@example.com")
account.id = "account-1"

View File

@ -1,3 +1,4 @@
from inspect import unwrap
from unittest.mock import MagicMock, patch
import pytest
@ -19,12 +20,6 @@ from graphon.variables.types import SegmentType
from models.account import Account, TenantAccountRole
def unwrap(func):
while hasattr(func, "__wrapped__"):
func = func.__wrapped__
return func
@pytest.fixture
def fake_db():
db = MagicMock()

View File

@ -1,4 +1,5 @@
from datetime import datetime
from inspect import unwrap
from unittest.mock import MagicMock, patch
from flask import Flask
@ -7,12 +8,6 @@ import controllers.console.explore.banner as banner_module
from models.enums import BannerStatus
def unwrap(func):
while hasattr(func, "__wrapped__"):
func = func.__wrapped__
return func
class TestBannerApi:
def test_get_banners_with_requested_language(self, app: Flask):
api = banner_module.BannerApi()

View File

@ -13,10 +13,7 @@ type Payload = dict[str, object]
type PayloadPatch = Callable[[Payload], AbstractContextManager[object]]
def unwrap(func):
while hasattr(func, "__wrapped__"):
func = func.__wrapped__
return func
from inspect import unwrap
@pytest.fixture

View File

@ -1,3 +1,4 @@
from inspect import unwrap
from unittest.mock import MagicMock, patch
import pytest
@ -7,12 +8,6 @@ from controllers.console.app.error import AppUnavailableError
from models.model import AppMode
def unwrap(func):
while hasattr(func, "__wrapped__"):
func = func.__wrapped__
return func
class TestAppParameterApi:
def test_get_app_none(self):
api = module.AppParameterApi()

View File

@ -1,3 +1,4 @@
from inspect import unwrap
from unittest.mock import ANY, patch
from flask import Flask
@ -7,12 +8,6 @@ from models import Account
from models.model import AppMode, IconType
def unwrap(func):
while hasattr(func, "__wrapped__"):
func = func.__wrapped__
return func
def make_account(interface_language: str | None) -> Account:
account = Account(name="Test User", email="user@example.com")
account.id = "account-1"

View File

@ -1,3 +1,4 @@
from inspect import unwrap
from unittest.mock import MagicMock, PropertyMock, patch
from uuid import uuid4
@ -10,12 +11,6 @@ from controllers.console.explore.error import NotCompletionAppError
from services.errors.message import MessageNotExistsError
def unwrap(func):
while hasattr(func, "__wrapped__"):
func = func.__wrapped__
return func
def make_saved_message():
msg = MagicMock()
msg.id = str(uuid4())

View File

@ -1,3 +1,4 @@
from inspect import unwrap
from unittest.mock import MagicMock, patch
import pytest
@ -14,12 +15,6 @@ from models.model import AppMode
from services.errors.llm import InvokeRateLimitError
def unwrap(func):
while hasattr(func, "__wrapped__"):
func = func.__wrapped__
return func
@pytest.fixture
def app():
app = Flask(__name__)

View File

@ -18,12 +18,6 @@ from controllers.console.explore.wraps import (
)
def unwrap(func):
while hasattr(func, "__wrapped__"):
func = func.__wrapped__
return func
def test_installed_app_required_not_found():
@installed_app_required
def view(installed_app):

View File

@ -84,7 +84,7 @@ def test_system_variables_returns_empty_list(app):
assert result == WorkflowDraftVariableList(variables=[])
def test_delete_variable_collection_deletes_current_user_variables(app, monkeypatch):
def test_delete_variable_collection_deletes_current_user_variables(app: Flask, monkeypatch: pytest.MonkeyPatch):
draft_var_service = SimpleNamespace(delete_user_workflow_variables=Mock())
monkeypatch.setattr(module, "WorkflowDraftVariableService", Mock(return_value=draft_var_service))
db_session = Mock()
@ -101,7 +101,7 @@ def test_delete_variable_collection_deletes_current_user_variables(app, monkeypa
db_session.commit.assert_called_once()
def test_variable_collection_get_raises_when_draft_workflow_missing(app, monkeypatch):
def test_variable_collection_get_raises_when_draft_workflow_missing(app: Flask, monkeypatch: pytest.MonkeyPatch):
monkeypatch.setattr(
module,
"SnippetService",
@ -116,7 +116,7 @@ def test_variable_collection_get_raises_when_draft_workflow_missing(app, monkeyp
handler(api, _make_account(), snippet=SimpleNamespace(id="snippet-1"))
def test_node_variable_collection_get_lists_node_variables(app, monkeypatch):
def test_node_variable_collection_get_lists_node_variables(app: Flask, monkeypatch: pytest.MonkeyPatch):
variables = WorkflowDraftVariableList(variables=[SimpleNamespace(id="var-1")])
list_node_variables = Mock(return_value=variables)
@ -149,7 +149,7 @@ def test_node_variable_collection_get_lists_node_variables(app, monkeypatch):
list_node_variables.assert_called_once_with("snippet-1", "llm-1", user_id="user-1")
def test_node_variable_collection_delete_deletes_node_variables(app, monkeypatch):
def test_node_variable_collection_delete_deletes_node_variables(app: Flask, monkeypatch: pytest.MonkeyPatch):
delete_node_variables = Mock()
draft_var_service = SimpleNamespace(delete_node_variables=delete_node_variables)
monkeypatch.setattr(module, "WorkflowDraftVariableService", Mock(return_value=draft_var_service))
@ -168,7 +168,7 @@ def test_node_variable_collection_delete_deletes_node_variables(app, monkeypatch
db_session.commit.assert_called_once()
def test_variable_patch_returns_variable_when_no_changes(app, monkeypatch):
def test_variable_patch_returns_variable_when_no_changes(app: Flask, monkeypatch: pytest.MonkeyPatch):
variable = SimpleNamespace(id="var-1", app_id="snippet-1", user_id="user-1", node_id="llm-1")
draft_var_service = SimpleNamespace(get_variable=Mock(return_value=variable), update_variable=Mock())
db_session = Mock()
@ -192,7 +192,7 @@ def test_variable_patch_returns_variable_when_no_changes(app, monkeypatch):
db_session.commit.assert_not_called()
def test_variable_delete_deletes_variable(app, monkeypatch):
def test_variable_delete_deletes_variable(app: Flask, monkeypatch: pytest.MonkeyPatch):
variable = SimpleNamespace(id="var-1", app_id="snippet-1", user_id="user-1", node_id="llm-1")
delete_variable = Mock()
draft_var_service = SimpleNamespace(get_variable=Mock(return_value=variable), delete_variable=delete_variable)
@ -212,7 +212,7 @@ def test_variable_delete_deletes_variable(app, monkeypatch):
db_session.commit.assert_called_once()
def test_variable_reset_returns_no_content_when_reset_result_is_none(app, monkeypatch):
def test_variable_reset_returns_no_content_when_reset_result_is_none(app: Flask, monkeypatch: pytest.MonkeyPatch):
variable = SimpleNamespace(id="var-1", app_id="snippet-1", user_id="user-1", node_id="llm-1")
draft_workflow = SimpleNamespace(id="workflow-1")
draft_var_service = SimpleNamespace(
@ -240,7 +240,7 @@ def test_variable_reset_returns_no_content_when_reset_result_is_none(app, monkey
db_session.commit.assert_called_once()
def test_environment_variables_returns_workflow_environment_variables(app, monkeypatch):
def test_environment_variables_returns_workflow_environment_variables(app: Flask, monkeypatch: pytest.MonkeyPatch):
env_var = SimpleNamespace(
id="env-1",
name="API_KEY",

View File

@ -1,14 +1,9 @@
from inspect import unwrap
from unittest.mock import patch
import controllers.console.spec as spec_module
def unwrap(func):
while hasattr(func, "__wrapped__"):
func = func.__wrapped__
return func
class TestSpecSchemaDefinitionsApi:
def test_get_success(self):
api = spec_module.SpecSchemaDefinitionsApi()

View File

@ -1,3 +1,4 @@
from inspect import unwrap
from unittest.mock import MagicMock, patch
from flask import Flask
@ -8,12 +9,6 @@ from controllers.console.workspace.agent_providers import (
)
def unwrap(func):
while hasattr(func, "__wrapped__"):
func = func.__wrapped__
return func
class TestAgentProviderListApi:
def test_get_success(self, app: Flask):
api = AgentProviderListApi()

View File

@ -1,4 +1,5 @@
from contextlib import nullcontext
from inspect import unwrap
from types import SimpleNamespace
from unittest.mock import MagicMock, patch
@ -26,12 +27,6 @@ from controllers.console.workspace.members import (
from services.errors.account import AccountAlreadyInTenantError
def unwrap(func):
while hasattr(func, "__wrapped__"):
func = func.__wrapped__
return func
class TestMemberListApi:
def test_get_success(self, app: Flask):
api = MemberListApi()

View File

@ -20,10 +20,7 @@ VALID_UUID = "123e4567-e89b-12d3-a456-426614174000"
INVALID_UUID = "123"
def unwrap(func):
while hasattr(func, "__wrapped__"):
func = func.__wrapped__
return func
from inspect import unwrap
class TestModelProviderListApi:

View File

@ -1,3 +1,4 @@
from inspect import unwrap
from types import SimpleNamespace
from unittest.mock import patch
@ -19,12 +20,6 @@ from graphon.model_runtime.entities.model_entities import ModelType
from graphon.model_runtime.errors.validate import CredentialsValidateFailedError
def unwrap(func):
while hasattr(func, "__wrapped__"):
func = func.__wrapped__
return func
class TestDefaultModelApi:
def test_get_success(self, app: Flask):
api = DefaultModelApi()

View File

@ -1,4 +1,5 @@
import types
from inspect import unwrap
from unittest.mock import patch
import pytest
@ -7,12 +8,6 @@ from werkzeug.exceptions import NotFound
import controllers.files.image_preview as module
def unwrap(func):
while hasattr(func, "__wrapped__"):
func = func.__wrapped__
return func
@pytest.fixture(autouse=True)
def mock_db():
"""

View File

@ -1,4 +1,5 @@
import types
from inspect import unwrap
from unittest.mock import patch
import pytest
@ -7,12 +8,6 @@ from werkzeug.exceptions import Forbidden, NotFound
import controllers.files.tool_files as module
def unwrap(func):
while hasattr(func, "__wrapped__"):
func = func.__wrapped__
return func
def fake_request(args: dict):
return types.SimpleNamespace(args=types.SimpleNamespace(to_dict=lambda flat=True: args))

View File

@ -1,5 +1,6 @@
import io
import types
from inspect import unwrap
from unittest.mock import patch
import pytest
@ -9,12 +10,6 @@ import controllers.files.upload as module
from core.workflow.file_reference import build_file_reference
def unwrap(func):
while hasattr(func, "__wrapped__"):
func = func.__wrapped__
return func
def fake_request(args: dict, file=None):
return types.SimpleNamespace(
args=types.SimpleNamespace(to_dict=lambda flat=True: args),

View File

@ -21,7 +21,7 @@ def mock_db_session(mocker: MockerFixture):
@pytest.fixture
def runner(mocker, mock_db_session):
def runner(mocker: MockerFixture, mock_db_session):
r = BaseAgentRunner.__new__(BaseAgentRunner)
r.tenant_id = "tenant"
r.user_id = "user"

View File

@ -17,7 +17,7 @@ from graphon.model_runtime.entities.message_entities import (
@pytest.fixture
def runner(mocker, dummy_tool_factory):
def runner(mocker: MockerFixture, dummy_tool_factory):
runner = CotCompletionAgentRunner.__new__(CotCompletionAgentRunner)
runner._instruction = "Test instruction"

View File

@ -32,7 +32,7 @@ def base_config(valid_uuid):
@pytest.fixture
def mock_dataset_service(mocker, valid_uuid):
def mock_dataset_service(mocker: MockerFixture, valid_uuid):
mock_dataset = MagicMock()
mock_dataset.tenant_id = "tenant1"

View File

@ -11,6 +11,8 @@ from __future__ import annotations
from types import SimpleNamespace
from typing import Any
import pytest
import core.app.features.annotation_reply.annotation_reply as annotation_mod
import core.moderation.input_moderation as input_moderation_mod
from core.app.apps.agent_app.app_generator import AgentAppGenerator
@ -42,7 +44,7 @@ def _make_entity(query: str = "hello") -> SimpleNamespace:
)
def _patch_moderation(monkeypatch, *, returns=None, raises: Exception | None = None) -> None:
def _patch_moderation(monkeypatch: pytest.MonkeyPatch, *, returns=None, raises: Exception | None = None) -> None:
class _FakeModeration:
def check(self, **kwargs: Any):
if raises is not None:
@ -52,7 +54,7 @@ def _patch_moderation(monkeypatch, *, returns=None, raises: Exception | None = N
monkeypatch.setattr(input_moderation_mod, "InputModeration", _FakeModeration)
def _patch_annotation(monkeypatch, *, reply=None) -> None:
def _patch_annotation(monkeypatch: pytest.MonkeyPatch, *, reply=None) -> None:
class _FakeAnnotation:
def query(self, **kwargs: Any):
return reply
@ -73,7 +75,7 @@ def _saved_user_query(events: list[Any]) -> str:
class TestRunInputGuards:
def test_no_guards_passes_through(self, monkeypatch):
def test_no_guards_passes_through(self, monkeypatch: pytest.MonkeyPatch):
_patch_moderation(monkeypatch, returns=(False, {}, "hello"))
_patch_annotation(monkeypatch, reply=None)
qm = _FakeQueueManager()
@ -89,7 +91,7 @@ class TestRunInputGuards:
assert query == "hello"
assert qm.events == []
def test_moderation_override_sanitizes_query(self, monkeypatch):
def test_moderation_override_sanitizes_query(self, monkeypatch: pytest.MonkeyPatch):
_patch_moderation(monkeypatch, returns=(True, {}, "[redacted]"))
_patch_annotation(monkeypatch, reply=None)
qm = _FakeQueueManager()
@ -105,7 +107,7 @@ class TestRunInputGuards:
assert query == "[redacted]"
assert qm.events == []
def test_moderation_block_short_circuits(self, monkeypatch):
def test_moderation_block_short_circuits(self, monkeypatch: pytest.MonkeyPatch):
_patch_moderation(monkeypatch, raises=ModerationError("blocked preset answer"))
_patch_annotation(monkeypatch, reply=None)
qm = _FakeQueueManager()
@ -122,7 +124,7 @@ class TestRunInputGuards:
assert _answer_text(qm.events) == "blocked preset answer"
assert _saved_user_query(qm.events) == "forbidden"
def test_annotation_hit_short_circuits(self, monkeypatch):
def test_annotation_hit_short_circuits(self, monkeypatch: pytest.MonkeyPatch):
_patch_moderation(monkeypatch, returns=(False, {}, "what is your name"))
_patch_annotation(monkeypatch, reply=SimpleNamespace(id="anno-1", content="I am the annotated Iris."))
qm = _FakeQueueManager()

View File

@ -44,7 +44,7 @@ def _snapshot() -> SimpleNamespace:
class TestResolveAgentById:
def test_success_returns_agent_snapshot_soul(self, monkeypatch):
def test_success_returns_agent_snapshot_soul(self, monkeypatch: pytest.MonkeyPatch):
agent = SimpleNamespace(id="agent-1")
snapshot = _snapshot()
_patch_session(monkeypatch, [agent, snapshot])
@ -59,24 +59,24 @@ class TestResolveAgentById:
assert soul.model is not None
assert soul.model.model == "gpt-4o-mini"
def test_agent_missing_raises(self, monkeypatch):
def test_agent_missing_raises(self, monkeypatch: pytest.MonkeyPatch):
_patch_session(monkeypatch, [None])
with pytest.raises(AgentAppGeneratorError, match="Agent not found"):
AgentAppGenerator._resolve_agent_by_id(tenant_id="t1", agent_id="x", snapshot_id="snap-1")
def test_no_published_version_raises(self, monkeypatch):
def test_no_published_version_raises(self, monkeypatch: pytest.MonkeyPatch):
_patch_session(monkeypatch, [SimpleNamespace(id="agent-1")])
with pytest.raises(AgentAppGeneratorError, match="no published version"):
AgentAppGenerator._resolve_agent_by_id(tenant_id="t1", agent_id="agent-1", snapshot_id=None)
def test_snapshot_missing_raises(self, monkeypatch):
def test_snapshot_missing_raises(self, monkeypatch: pytest.MonkeyPatch):
_patch_session(monkeypatch, [SimpleNamespace(id="agent-1"), None])
with pytest.raises(AgentAppGeneratorError, match="published version not found"):
AgentAppGenerator._resolve_agent_by_id(tenant_id="t1", agent_id="agent-1", snapshot_id="snap-1")
class TestResolveAgent:
def test_success_chains_to_resolve_by_id(self, monkeypatch):
def test_success_chains_to_resolve_by_id(self, monkeypatch: pytest.MonkeyPatch):
bound_agent = SimpleNamespace(id="agent-1", active_config_snapshot_id="snap-1")
inner_agent = SimpleNamespace(id="agent-1")
snapshot = _snapshot()
@ -90,7 +90,7 @@ class TestResolveAgent:
assert snap is snapshot
assert soul.model is not None
def test_unbound_app_raises(self, monkeypatch):
def test_unbound_app_raises(self, monkeypatch: pytest.MonkeyPatch):
_patch_session(monkeypatch, [None])
app_model = SimpleNamespace(id="app-1", tenant_id="t1")
with pytest.raises(AgentAppGeneratorError, match="has no bound Agent"):

View File

@ -288,7 +288,7 @@ def test_advanced_chat_pause_resume_matches_baseline(mocker: MockerFixture):
assert resumed_state.outputs == baseline_outputs
def test_resume_emits_resumption_start_reason(mocker) -> None:
def test_resume_emits_resumption_start_reason(mocker: MockerFixture) -> None:
_patch_tool_node(mocker)
paused_state = _build_runtime_state("resume-reason")

View File

@ -40,7 +40,7 @@ class DummyDocumentExtractorNode(DummyNode):
class TestDifyNodeFactory:
@staticmethod
def _stub_node_resolution(monkeypatch, node_class):
def _stub_node_resolution(monkeypatch: pytest.MonkeyPatch, node_class):
monkeypatch.setattr(
"core.workflow.node_factory.resolve_workflow_node_class",
lambda **_kwargs: node_class,

View File

@ -89,7 +89,9 @@ def test_get_datasource_runtime_delegates_to_provider_controller(mocker: MockerF
),
],
)
def test_get_datasource_plugin_provider_creates_controller_and_caches(mocker, datasource_type, controller_path):
def test_get_datasource_plugin_provider_creates_controller_and_caches(
mocker: MockerFixture, datasource_type, controller_path
):
_invalidate_recyclable_contextvars()
provider_entity = types.SimpleNamespace(declaration=object(), plugin_id="plugin", plugin_unique_identifier="uniq")

View File

@ -36,7 +36,7 @@ def _signed_url(*, base_url: str, path: str, payload: str, secret: str = "test-s
return f"{base_url}{path}?{query}"
def _patch_file_fetcher_config(monkeypatch):
def _patch_file_fetcher_config(monkeypatch: pytest.MonkeyPatch):
monkeypatch.setattr(remote_fetcher.dify_config, "FILES_URL", "http://localhost:5001")
monkeypatch.setattr(remote_fetcher.dify_config, "INTERNAL_FILES_URL", "http://api:5001")
monkeypatch.setattr(remote_fetcher.dify_config, "SECRET_KEY", "test-secret")
@ -44,7 +44,7 @@ def _patch_file_fetcher_config(monkeypatch):
monkeypatch.setattr(remote_fetcher.time, "time", lambda: 1700000100)
def _patch_session(monkeypatch):
def _patch_session(monkeypatch: pytest.MonkeyPatch):
session = MagicMock()
session_cm = MagicMock()
session_cm.__enter__.return_value = session
@ -53,19 +53,19 @@ def _patch_session(monkeypatch):
return session
def _patch_ssrf_make_request(monkeypatch, response=None):
def _patch_ssrf_make_request(monkeypatch: pytest.MonkeyPatch, response=None):
make_request = MagicMock(return_value=response) if response is not None else MagicMock()
monkeypatch.setattr(remote_fetcher.ssrf_proxy, "make_request", make_request)
return make_request
def _patch_signer_times(monkeypatch):
def _patch_signer_times(monkeypatch: pytest.MonkeyPatch):
monkeypatch.setattr("core.datasource.datasource_file_manager.time.time", lambda: 1700000000)
monkeypatch.setattr("core.tools.signature.time.time", lambda: 1700000000)
monkeypatch.setattr("core.tools.tool_file_manager.time.time", lambda: 1700000000)
def test_get_signed_upload_file_url_reads_storage_without_ssrf(monkeypatch):
def test_get_signed_upload_file_url_reads_storage_without_ssrf(monkeypatch: pytest.MonkeyPatch):
_patch_file_fetcher_config(monkeypatch)
session = _patch_session(monkeypatch)
upload_file = SimpleNamespace(
@ -102,7 +102,7 @@ def test_get_signed_upload_file_url_reads_storage_without_ssrf(monkeypatch):
ssrf_make_request.assert_not_called()
def test_make_request_resolves_upload_preview_url_generated_by_signer(monkeypatch):
def test_make_request_resolves_upload_preview_url_generated_by_signer(monkeypatch: pytest.MonkeyPatch):
_patch_file_fetcher_config(monkeypatch)
_patch_signer_times(monkeypatch)
session = _patch_session(monkeypatch)
@ -132,7 +132,7 @@ def test_make_request_resolves_upload_preview_url_generated_by_signer(monkeypatc
ssrf_make_request.assert_not_called()
def test_make_request_resolves_sign_tool_file_url_with_empty_extension(monkeypatch):
def test_make_request_resolves_sign_tool_file_url_with_empty_extension(monkeypatch: pytest.MonkeyPatch):
_patch_file_fetcher_config(monkeypatch)
_patch_signer_times(monkeypatch)
session = _patch_session(monkeypatch)
@ -161,7 +161,7 @@ def test_make_request_resolves_sign_tool_file_url_with_empty_extension(monkeypat
ssrf_make_request.assert_not_called()
def test_make_request_resolves_tool_manager_url_with_empty_extension(monkeypatch):
def test_make_request_resolves_tool_manager_url_with_empty_extension(monkeypatch: pytest.MonkeyPatch):
_patch_file_fetcher_config(monkeypatch)
_patch_signer_times(monkeypatch)
session = _patch_session(monkeypatch)
@ -189,7 +189,7 @@ def test_make_request_resolves_tool_manager_url_with_empty_extension(monkeypatch
ssrf_make_request.assert_not_called()
def test_make_request_resolves_datasource_manager_url_with_empty_extension(monkeypatch):
def test_make_request_resolves_datasource_manager_url_with_empty_extension(monkeypatch: pytest.MonkeyPatch):
_patch_file_fetcher_config(monkeypatch)
_patch_signer_times(monkeypatch)
_patch_session(monkeypatch)
@ -222,7 +222,7 @@ def test_make_request_resolves_datasource_manager_url_with_empty_extension(monke
ssrf_make_request.assert_not_called()
def test_head_signed_upload_file_url_returns_metadata_without_storage_content(monkeypatch):
def test_head_signed_upload_file_url_returns_metadata_without_storage_content(monkeypatch: pytest.MonkeyPatch):
_patch_file_fetcher_config(monkeypatch)
session = _patch_session(monkeypatch)
upload_file = SimpleNamespace(
@ -259,7 +259,7 @@ def test_head_signed_upload_file_url_returns_metadata_without_storage_content(mo
ssrf_make_request.assert_not_called()
def test_make_request_get_signed_upload_file_url_reads_storage_without_ssrf(monkeypatch):
def test_make_request_get_signed_upload_file_url_reads_storage_without_ssrf(monkeypatch: pytest.MonkeyPatch):
_patch_file_fetcher_config(monkeypatch)
_patch_session(monkeypatch)
upload_file = SimpleNamespace(
@ -291,7 +291,7 @@ def test_make_request_get_signed_upload_file_url_reads_storage_without_ssrf(monk
ssrf_make_request.assert_not_called()
def test_make_request_head_signed_upload_file_url_returns_metadata_without_ssrf(monkeypatch):
def test_make_request_head_signed_upload_file_url_returns_metadata_without_ssrf(monkeypatch: pytest.MonkeyPatch):
_patch_file_fetcher_config(monkeypatch)
_patch_session(monkeypatch)
upload_file = SimpleNamespace(
@ -325,7 +325,7 @@ def test_make_request_head_signed_upload_file_url_returns_metadata_without_ssrf(
ssrf_make_request.assert_not_called()
def test_make_request_get_unsigned_dify_url_delegates_to_ssrf_proxy(monkeypatch):
def test_make_request_get_unsigned_dify_url_delegates_to_ssrf_proxy(monkeypatch: pytest.MonkeyPatch):
_patch_file_fetcher_config(monkeypatch)
get_upload_file = MagicMock()
monkeypatch.setattr(remote_fetcher._file_access_controller, "get_upload_file", get_upload_file)
@ -345,7 +345,7 @@ def test_make_request_get_unsigned_dify_url_delegates_to_ssrf_proxy(monkeypatch)
)
def test_make_request_post_signed_upload_file_url_delegates_to_ssrf_proxy(monkeypatch):
def test_make_request_post_signed_upload_file_url_delegates_to_ssrf_proxy(monkeypatch: pytest.MonkeyPatch):
_patch_file_fetcher_config(monkeypatch)
get_upload_file = MagicMock()
monkeypatch.setattr(remote_fetcher._file_access_controller, "get_upload_file", get_upload_file)
@ -369,7 +369,7 @@ def test_make_request_post_signed_upload_file_url_delegates_to_ssrf_proxy(monkey
)
def test_get_signed_image_preview_url_uses_image_preview_signature(monkeypatch):
def test_get_signed_image_preview_url_uses_image_preview_signature(monkeypatch: pytest.MonkeyPatch):
_patch_file_fetcher_config(monkeypatch)
_patch_session(monkeypatch)
upload_file = SimpleNamespace(
@ -401,7 +401,7 @@ def test_get_signed_image_preview_url_uses_image_preview_signature(monkeypatch):
ssrf_make_request.assert_not_called()
def test_image_preview_url_with_file_preview_signature_delegates_to_ssrf_proxy(monkeypatch):
def test_image_preview_url_with_file_preview_signature_delegates_to_ssrf_proxy(monkeypatch: pytest.MonkeyPatch):
_patch_file_fetcher_config(monkeypatch)
proxy_response = httpx.Response(403, request=httpx.Request("GET", "http://localhost:5001/bad"))
ssrf_make_request = _patch_ssrf_make_request(monkeypatch, proxy_response)
@ -421,7 +421,7 @@ def test_image_preview_url_with_file_preview_signature_delegates_to_ssrf_proxy(m
)
def test_duplicate_signature_query_value_delegates_to_ssrf_proxy(monkeypatch):
def test_duplicate_signature_query_value_delegates_to_ssrf_proxy(monkeypatch: pytest.MonkeyPatch):
_patch_file_fetcher_config(monkeypatch)
url = (
_signed_url(
@ -444,7 +444,7 @@ def test_duplicate_signature_query_value_delegates_to_ssrf_proxy(monkeypatch):
)
def test_malformed_timestamp_delegates_to_ssrf_proxy(monkeypatch):
def test_malformed_timestamp_delegates_to_ssrf_proxy(monkeypatch: pytest.MonkeyPatch):
_patch_file_fetcher_config(monkeypatch)
url = _signed_url(
base_url="http://localhost:5001",
@ -464,7 +464,7 @@ def test_malformed_timestamp_delegates_to_ssrf_proxy(monkeypatch):
)
def test_expired_signature_delegates_to_ssrf_proxy(monkeypatch):
def test_expired_signature_delegates_to_ssrf_proxy(monkeypatch: pytest.MonkeyPatch):
_patch_file_fetcher_config(monkeypatch)
monkeypatch.setattr(remote_fetcher.time, "time", lambda: 1700004001)
url = _signed_url(
@ -485,7 +485,7 @@ def test_expired_signature_delegates_to_ssrf_proxy(monkeypatch):
)
def test_invalid_signature_delegates_to_ssrf_proxy(monkeypatch):
def test_invalid_signature_delegates_to_ssrf_proxy(monkeypatch: pytest.MonkeyPatch):
_patch_file_fetcher_config(monkeypatch)
proxy_response = httpx.Response(403, request=httpx.Request("GET", "http://localhost:5001/bad"))
ssrf_make_request = _patch_ssrf_make_request(monkeypatch, proxy_response)
@ -502,7 +502,7 @@ def test_invalid_signature_delegates_to_ssrf_proxy(monkeypatch):
)
def test_host_mismatch_delegates_to_ssrf_proxy(monkeypatch):
def test_host_mismatch_delegates_to_ssrf_proxy(monkeypatch: pytest.MonkeyPatch):
_patch_file_fetcher_config(monkeypatch)
url = _signed_url(
base_url="http://example.com",
@ -522,7 +522,7 @@ def test_host_mismatch_delegates_to_ssrf_proxy(monkeypatch):
)
def test_unsupported_dify_path_delegates_to_ssrf_proxy(monkeypatch):
def test_unsupported_dify_path_delegates_to_ssrf_proxy(monkeypatch: pytest.MonkeyPatch):
_patch_file_fetcher_config(monkeypatch)
url = _signed_url(
base_url="http://localhost:5001",
@ -543,7 +543,7 @@ def test_unsupported_dify_path_delegates_to_ssrf_proxy(monkeypatch):
)
def test_invalid_url_scheme_delegates_to_ssrf_proxy(monkeypatch):
def test_invalid_url_scheme_delegates_to_ssrf_proxy(monkeypatch: pytest.MonkeyPatch):
_patch_file_fetcher_config(monkeypatch)
url = f"file:///tmp/files/{UPLOAD_FILE_ID}/file-preview?timestamp=1700000000&nonce=nonce&sign=ignored"
proxy_response = httpx.Response(403, request=httpx.Request("GET", url))
@ -559,7 +559,7 @@ def test_invalid_url_scheme_delegates_to_ssrf_proxy(monkeypatch):
)
def test_invalid_url_port_delegates_to_ssrf_proxy(monkeypatch):
def test_invalid_url_port_delegates_to_ssrf_proxy(monkeypatch: pytest.MonkeyPatch):
_patch_file_fetcher_config(monkeypatch)
url = f"http://localhost:invalid/files/{UPLOAD_FILE_ID}/file-preview?timestamp=1700000000&nonce=nonce&sign=ignored"
proxy_response = httpx.Response(403, request=httpx.Request("GET", "http://proxy.example/fallback"))
@ -575,7 +575,7 @@ def test_invalid_url_port_delegates_to_ssrf_proxy(monkeypatch):
)
def test_invalid_configured_file_origin_delegates_to_ssrf_proxy(monkeypatch):
def test_invalid_configured_file_origin_delegates_to_ssrf_proxy(monkeypatch: pytest.MonkeyPatch):
_patch_file_fetcher_config(monkeypatch)
monkeypatch.setattr(remote_fetcher.dify_config, "FILES_URL", "")
monkeypatch.setattr(remote_fetcher.dify_config, "INTERNAL_FILES_URL", "file:///tmp/files")
@ -597,7 +597,7 @@ def test_invalid_configured_file_origin_delegates_to_ssrf_proxy(monkeypatch):
)
def test_signed_upload_file_url_returns_404_when_record_missing(monkeypatch):
def test_signed_upload_file_url_returns_404_when_record_missing(monkeypatch: pytest.MonkeyPatch):
_patch_file_fetcher_config(monkeypatch)
_patch_session(monkeypatch)
get_upload_file = MagicMock(return_value=None)
@ -617,7 +617,7 @@ def test_signed_upload_file_url_returns_404_when_record_missing(monkeypatch):
ssrf_make_request.assert_not_called()
def test_get_signed_tool_file_url_reads_storage_without_ssrf(monkeypatch):
def test_get_signed_tool_file_url_reads_storage_without_ssrf(monkeypatch: pytest.MonkeyPatch):
_patch_file_fetcher_config(monkeypatch)
session = _patch_session(monkeypatch)
tool_file = SimpleNamespace(
@ -651,7 +651,7 @@ def test_get_signed_tool_file_url_reads_storage_without_ssrf(monkeypatch):
ssrf_make_request.assert_not_called()
def test_signed_tool_file_url_returns_404_when_record_missing(monkeypatch):
def test_signed_tool_file_url_returns_404_when_record_missing(monkeypatch: pytest.MonkeyPatch):
_patch_file_fetcher_config(monkeypatch)
_patch_session(monkeypatch)
get_tool_file = MagicMock(return_value=None)
@ -671,7 +671,7 @@ def test_signed_tool_file_url_returns_404_when_record_missing(monkeypatch):
ssrf_make_request.assert_not_called()
def test_get_signed_datasource_file_url_reads_upload_storage_without_ssrf(monkeypatch):
def test_get_signed_datasource_file_url_reads_upload_storage_without_ssrf(monkeypatch: pytest.MonkeyPatch):
_patch_file_fetcher_config(monkeypatch)
_patch_session(monkeypatch)
upload_file = SimpleNamespace(
@ -705,7 +705,7 @@ def test_get_signed_datasource_file_url_reads_upload_storage_without_ssrf(monkey
ssrf_make_request.assert_not_called()
def test_get_signed_datasource_file_url_reads_tool_storage_when_upload_missing(monkeypatch):
def test_get_signed_datasource_file_url_reads_tool_storage_when_upload_missing(monkeypatch: pytest.MonkeyPatch):
_patch_file_fetcher_config(monkeypatch)
_patch_session(monkeypatch)
tool_file = SimpleNamespace(
@ -740,7 +740,7 @@ def test_get_signed_datasource_file_url_reads_tool_storage_when_upload_missing(m
ssrf_make_request.assert_not_called()
def test_signed_datasource_file_url_returns_404_when_records_missing(monkeypatch):
def test_signed_datasource_file_url_returns_404_when_records_missing(monkeypatch: pytest.MonkeyPatch):
_patch_file_fetcher_config(monkeypatch)
_patch_session(monkeypatch)
get_upload_file = MagicMock(return_value=None)

View File

@ -81,7 +81,7 @@ def patched_runtime(monkeypatch: pytest.MonkeyPatch):
return SimpleNamespace(session=session, storage=storage, lock=lock)
def test_create_indexes_documents_and_returns_self(monkeypatch, patched_runtime):
def test_create_indexes_documents_and_returns_self(monkeypatch: pytest.MonkeyPatch, patched_runtime):
dataset = _dataset(_dataset_keyword_table(), keyword_number=2)
keyword = Jieba(dataset)
handler = MagicMock()
@ -111,7 +111,7 @@ def test_create_indexes_documents_and_returns_self(monkeypatch, patched_runtime)
patched_runtime.lock.assert_called_once_with("keyword_indexing_lock_dataset-1", timeout=600)
def test_add_texts_supports_keywords_list_and_extract_fallback(monkeypatch, patched_runtime):
def test_add_texts_supports_keywords_list_and_extract_fallback(monkeypatch: pytest.MonkeyPatch, patched_runtime):
keyword = Jieba(_dataset(_dataset_keyword_table(), keyword_number=3))
handler = MagicMock()
handler.extract_keywords.return_value = {"auto"}
@ -135,7 +135,7 @@ def test_add_texts_supports_keywords_list_and_extract_fallback(monkeypatch, patc
keyword._save_dataset_keyword_table.assert_called_once()
def test_add_texts_without_keywords_list_always_uses_extractor(monkeypatch, patched_runtime):
def test_add_texts_without_keywords_list_always_uses_extractor(monkeypatch: pytest.MonkeyPatch, patched_runtime):
keyword = Jieba(_dataset(_dataset_keyword_table(), keyword_number=1))
handler = MagicMock()
handler.extract_keywords.return_value = {"from-extractor"}
@ -162,7 +162,7 @@ def test_text_exists_handles_missing_and_existing_keyword_table(monkeypatch: pyt
assert keyword.text_exists("node-x") is False
def test_delete_by_ids_updates_table_when_present(monkeypatch, patched_runtime):
def test_delete_by_ids_updates_table_when_present(monkeypatch: pytest.MonkeyPatch, patched_runtime):
keyword = Jieba(_dataset(_dataset_keyword_table()))
monkeypatch.setattr(keyword, "_get_dataset_keyword_table", MagicMock(return_value={"k": {"node-1", "node-2"}}))
monkeypatch.setattr(keyword, "_delete_ids_from_keyword_table", MagicMock(return_value={"k": {"node-2"}}))
@ -174,7 +174,7 @@ def test_delete_by_ids_updates_table_when_present(monkeypatch, patched_runtime):
keyword._save_dataset_keyword_table.assert_called_once_with({"k": {"node-2"}})
def test_delete_by_ids_saves_none_when_keyword_table_is_missing(monkeypatch, patched_runtime):
def test_delete_by_ids_saves_none_when_keyword_table_is_missing(monkeypatch: pytest.MonkeyPatch, patched_runtime):
keyword = Jieba(_dataset(_dataset_keyword_table()))
monkeypatch.setattr(keyword, "_get_dataset_keyword_table", MagicMock(return_value=None))
monkeypatch.setattr(keyword, "_delete_ids_from_keyword_table", MagicMock())
@ -186,7 +186,7 @@ def test_delete_by_ids_saves_none_when_keyword_table_is_missing(monkeypatch, pat
keyword._save_dataset_keyword_table.assert_called_once_with(None)
def test_search_returns_documents_in_rank_order_and_applies_filter(monkeypatch, patched_runtime):
def test_search_returns_documents_in_rank_order_and_applies_filter(monkeypatch: pytest.MonkeyPatch, patched_runtime):
class _FakeDocumentSegment:
dataset_id = _Field("dataset_id")
index_node_id = _Field("index_node_id")
@ -216,7 +216,7 @@ def test_search_returns_documents_in_rank_order_and_applies_filter(monkeypatch,
assert documents[0].metadata["doc_hash"] == "hash-2"
def test_delete_removes_keyword_table_and_optional_file(monkeypatch, patched_runtime):
def test_delete_removes_keyword_table_and_optional_file(monkeypatch: pytest.MonkeyPatch, patched_runtime):
db_keyword = _dataset_keyword_table(data_source_type="database")
file_keyword = _dataset_keyword_table(data_source_type="object_storage")
@ -232,7 +232,7 @@ def test_delete_removes_keyword_table_and_optional_file(monkeypatch, patched_run
assert patched_runtime.session.commit.call_count == 2
def test_save_dataset_keyword_table_to_database(monkeypatch, patched_runtime):
def test_save_dataset_keyword_table_to_database(monkeypatch: pytest.MonkeyPatch, patched_runtime):
dataset_keyword_table = _dataset_keyword_table(data_source_type="database")
keyword = Jieba(_dataset(dataset_keyword_table))
@ -243,7 +243,7 @@ def test_save_dataset_keyword_table_to_database(monkeypatch, patched_runtime):
patched_runtime.session.commit.assert_called_once()
def test_save_dataset_keyword_table_to_file_storage(monkeypatch, patched_runtime):
def test_save_dataset_keyword_table_to_file_storage(monkeypatch: pytest.MonkeyPatch, patched_runtime):
dataset_keyword_table = _dataset_keyword_table(data_source_type="file")
keyword = Jieba(_dataset(dataset_keyword_table))
patched_runtime.storage.exists.return_value = True
@ -257,7 +257,7 @@ def test_save_dataset_keyword_table_to_file_storage(monkeypatch, patched_runtime
assert isinstance(save_args[1], bytes)
def test_get_dataset_keyword_table_returns_existing_table_data(monkeypatch, patched_runtime):
def test_get_dataset_keyword_table_returns_existing_table_data(monkeypatch: pytest.MonkeyPatch, patched_runtime):
existing = _dataset_keyword_table(
keyword_table_dict={"__type__": "keyword_table", "__data__": {"table": {"kw": ["node-1"]}}}
)
@ -269,7 +269,7 @@ def test_get_dataset_keyword_table_returns_existing_table_data(monkeypatch, patc
assert keyword_with_missing_payload._get_dataset_keyword_table() == {}
def test_get_dataset_keyword_table_creates_table_when_missing(monkeypatch, patched_runtime):
def test_get_dataset_keyword_table_creates_table_when_missing(monkeypatch: pytest.MonkeyPatch, patched_runtime):
created_tables: list[SimpleNamespace] = []
def _fake_dataset_keyword_table(**kwargs):
@ -323,7 +323,7 @@ def test_retrieve_ids_by_query_ranks_by_keyword_frequency(monkeypatch: pytest.Mo
assert ranked_ids == ["node-2"]
def test_update_segment_keywords_updates_when_segment_exists(monkeypatch, patched_runtime):
def test_update_segment_keywords_updates_when_segment_exists(monkeypatch: pytest.MonkeyPatch, patched_runtime):
class _FakeDocumentSegment:
dataset_id = _Field("dataset_id")
index_node_id = _Field("index_node_id")

View File

@ -9,7 +9,7 @@ import pytest
from core.rag.models.document import Document
def _register_fake_factory_module(monkeypatch, module_path: str, class_name: str):
def _register_fake_factory_module(monkeypatch: pytest.MonkeyPatch, module_path: str, class_name: str):
fake_module = types.ModuleType(module_path)
fake_cls = type(class_name, (), {})
setattr(fake_module, class_name, fake_cls)

View File

@ -7,7 +7,10 @@ from core.tools.errors import ToolProviderNotFoundError
from events.event_handlers import delete_tool_parameters_cache_when_sync_draft_workflow as handler_module
def test_missing_tool_provider_does_not_log_error_traceback(monkeypatch, caplog: pytest.LogCaptureFixture):
def test_missing_tool_provider_does_not_log_error_traceback(
monkeypatch: pytest.MonkeyPatch,
caplog: pytest.LogCaptureFixture,
):
app = SimpleNamespace(id="workflow-id", tenant_id="tenant-id")
workflow = SimpleNamespace(
graph_dict={

View File

@ -16,7 +16,7 @@ from libs.archive_storage import (
BUCKET_NAME = "archive-bucket"
def _configure_storage(monkeypatch, **overrides):
def _configure_storage(monkeypatch: pytest.MonkeyPatch, **overrides):
defaults = {
"ARCHIVE_STORAGE_ENABLED": True,
"ARCHIVE_STORAGE_ENDPOINT": "https://storage.example.com",

View File

@ -3,7 +3,6 @@ import posixpath
from unittest.mock import MagicMock
import pytest
from _pytest.monkeypatch import MonkeyPatch
from oss2 import Bucket
from oss2.models import GetObjectResult, PutObjectResult
@ -85,7 +84,7 @@ MOCK = os.getenv("MOCK_SWITCH", "false").lower() == "true"
@pytest.fixture
def setup_aliyun_oss_mock(monkeypatch: MonkeyPatch):
def setup_aliyun_oss_mock(monkeypatch: pytest.MonkeyPatch):
if MOCK:
monkeypatch.setattr(Bucket, "__init__", MockAliyunOssClass.__init__)
monkeypatch.setattr(Bucket, "put_object", MockAliyunOssClass.put_object)

View File

@ -5,7 +5,6 @@ from io import BytesIO
from types import SimpleNamespace
import pytest
from _pytest.monkeypatch import MonkeyPatch
from baidubce.services.bos.bos_client import BosClient
from tests.unit_tests.oss.__mock.base import (
@ -55,7 +54,7 @@ MOCK = os.getenv("MOCK_SWITCH", "false").lower() == "true"
@pytest.fixture
def setup_baidu_obs_mock(monkeypatch: MonkeyPatch):
def setup_baidu_obs_mock(monkeypatch: pytest.MonkeyPatch):
if MOCK:
monkeypatch.setattr(BosClient, "__init__", MockBaiduObsClass.__init__)
monkeypatch.setattr(BosClient, "put_object", MockBaiduObsClass.put_object)

View File

@ -4,7 +4,6 @@ from pathlib import Path
from unittest.mock import MagicMock, mock_open, patch
import pytest
from _pytest.monkeypatch import MonkeyPatch
from tests.unit_tests.oss.__mock.base import (
get_example_data,
@ -40,7 +39,7 @@ MOCK = os.getenv("MOCK_SWITCH", "false").lower() == "true"
@pytest.fixture
def setup_local_fs_mock(monkeypatch: MonkeyPatch):
def setup_local_fs_mock(monkeypatch: pytest.MonkeyPatch):
if MOCK:
monkeypatch.setattr(Path, "write_bytes", MockLocalFSClass.write_bytes)
monkeypatch.setattr(Path, "read_bytes", MockLocalFSClass.read_bytes)

View File

@ -2,7 +2,6 @@ import os
from unittest.mock import MagicMock
import pytest
from _pytest.monkeypatch import MonkeyPatch
from qcloud_cos import CosS3Client
from qcloud_cos.streambody import StreamBody
@ -67,7 +66,7 @@ MOCK = os.getenv("MOCK_SWITCH", "false").lower() == "true"
@pytest.fixture
def setup_tencent_cos_mock(monkeypatch: MonkeyPatch):
def setup_tencent_cos_mock(monkeypatch: pytest.MonkeyPatch):
if MOCK:
monkeypatch.setattr(CosS3Client, "__init__", MockTencentCosClass.__init__)
monkeypatch.setattr(CosS3Client, "put_object", MockTencentCosClass.put_object)

View File

@ -3,7 +3,6 @@ from collections import UserDict
from unittest.mock import MagicMock
import pytest
from _pytest.monkeypatch import MonkeyPatch
from tos import TosClientV2
from tos.clientv2 import DeleteObjectOutput, GetObjectOutput, HeadObjectOutput, PutObjectOutput
@ -76,7 +75,7 @@ MOCK = os.getenv("MOCK_SWITCH", "false").lower() == "true"
@pytest.fixture
def setup_volcengine_tos_mock(monkeypatch: MonkeyPatch):
def setup_volcengine_tos_mock(monkeypatch: pytest.MonkeyPatch):
if MOCK:
monkeypatch.setattr(TosClientV2, "__init__", MockVolcengineTosClass.__init__)
monkeypatch.setattr(TosClientV2, "put_object", MockVolcengineTosClass.put_object)

View File

@ -460,7 +460,7 @@ def test_composer_save_helpers_create_and_rebind_agents(monkeypatch: pytest.Monk
assert new_version_binding.current_snapshot_id == "new-version-1"
def test_node_job_only_updates_inline_agent_soul(monkeypatch):
def test_node_job_only_updates_inline_agent_soul(monkeypatch: pytest.MonkeyPatch):
fake_session = FakeSession()
monkeypatch.setattr(composer_service.db, "session", fake_session)
inline_agent = SimpleNamespace(
@ -532,7 +532,7 @@ def test_node_job_only_updates_inline_agent_soul(monkeypatch):
assert inline_agent.updated_by == "account-1"
def test_node_job_only_rejects_inline_binding_pointing_to_roster_agent(monkeypatch):
def test_node_job_only_rejects_inline_binding_pointing_to_roster_agent(monkeypatch: pytest.MonkeyPatch):
fake_session = FakeSession()
monkeypatch.setattr(composer_service.db, "session", fake_session)
current_snapshot = AgentConfigSnapshot(
@ -579,7 +579,7 @@ def test_node_job_only_rejects_inline_binding_pointing_to_roster_agent(monkeypat
)
def test_composer_create_agents_syncs_active_config_has_model(monkeypatch):
def test_composer_create_agents_syncs_active_config_has_model(monkeypatch: pytest.MonkeyPatch):
fake_session = FakeSession()
monkeypatch.setattr(composer_service.db, "session", fake_session)
monkeypatch.setattr(
@ -2570,7 +2570,7 @@ def test_save_workflow_composer_guards_drive_refs_for_existing_agent_strategies(
assert guarded["agent_id"] == "agent-1"
def test_save_workflow_composer_guards_drive_refs_for_inline_node_job_only(monkeypatch):
def test_save_workflow_composer_guards_drive_refs_for_inline_node_job_only(monkeypatch: pytest.MonkeyPatch):
payload = ComposerSavePayload.model_validate(
{
"variant": "workflow",
@ -2627,7 +2627,7 @@ def test_save_workflow_composer_guards_drive_refs_for_inline_node_job_only(monke
assert guarded == {"tenant_id": "t-1", "agent_id": "agent-1"}
def test_save_workflow_composer_skips_drive_refs_for_roster_node_job_only(monkeypatch):
def test_save_workflow_composer_skips_drive_refs_for_roster_node_job_only(monkeypatch: pytest.MonkeyPatch):
payload = ComposerSavePayload.model_validate(
{
"variant": "workflow",
@ -2681,7 +2681,7 @@ def test_save_workflow_composer_skips_drive_refs_for_roster_node_job_only(monkey
assert result == {"state": "ok", "validation": {"warnings": []}}
def test_remove_drive_refs_noop_when_skill_slug_unmatched(monkeypatch):
def test_remove_drive_refs_noop_when_skill_slug_unmatched(monkeypatch: pytest.MonkeyPatch):
soul_dict = {"skills_files": {"skills": [{"name": "Other", "skill_md_key": "other/SKILL.md"}], "files": []}}
_, captured, committed = _patch_remove_drive_refs_env(monkeypatch, soul_dict=soul_dict)
assert (

View File

@ -33,7 +33,7 @@ def _patch_soul_files(monkeypatch, files):
monkeypatch.setattr(SkillToolInferenceService, "_manifest_files_from_soul", staticmethod(lambda **kwargs: files))
def test_infer_returns_suggestions_with_inferred_from(monkeypatch):
def test_infer_returns_suggestions_with_inferred_from(monkeypatch: pytest.MonkeyPatch):
service, drive = _service()
_patch_soul_files(monkeypatch, ["SKILL.md", "scripts/transcribe.sh"])
raw = (
@ -53,7 +53,7 @@ def test_infer_returns_suggestions_with_inferred_from(monkeypatch):
drive.preview.assert_called_once_with(tenant_id="t-1", agent_id="a-1", key="audio-transcribe/SKILL.md")
def test_infer_threads_manifest_files_into_the_prompt(monkeypatch):
def test_infer_threads_manifest_files_into_the_prompt(monkeypatch: pytest.MonkeyPatch):
service, _ = _service()
_patch_soul_files(monkeypatch, ["scripts/run.sh"])
captured: dict[str, str] = {}
@ -69,7 +69,7 @@ def test_infer_threads_manifest_files_into_the_prompt(monkeypatch):
assert "ffmpeg" in captured["prompt"] # SKILL.md body present
def test_infer_not_inferable_passes_reason_through(monkeypatch):
def test_infer_not_inferable_passes_reason_through(monkeypatch: pytest.MonkeyPatch):
service, _ = _service()
_patch_soul_files(monkeypatch, [])
raw = '{"inferable": false, "cli_tools": [], "reason": "SKILL.md 未描述任何外部命令依赖"}'
@ -78,7 +78,7 @@ def test_infer_not_inferable_passes_reason_through(monkeypatch):
assert result == {"inferable": False, "cli_tools": [], "reason": "SKILL.md 未描述任何外部命令依赖"}
def test_infer_retries_once_then_422(monkeypatch):
def test_infer_retries_once_then_422(monkeypatch: pytest.MonkeyPatch):
service, _ = _service()
_patch_soul_files(monkeypatch, [])
calls: list[int] = []
@ -96,7 +96,7 @@ def test_infer_retries_once_then_422(monkeypatch):
assert exc_info.value.status_code == 422
def test_infer_repairs_slightly_malformed_json(monkeypatch):
def test_infer_repairs_slightly_malformed_json(monkeypatch: pytest.MonkeyPatch):
service, _ = _service()
_patch_soul_files(monkeypatch, [])
raw = 'Here you go: {"inferable": true, "cli_tools": [], "reason": null,}'
@ -126,7 +126,7 @@ def test_binary_skill_md_maps_to_404():
# ── real-path coverage: _invoke / _manifest_files_from_soul / passthrough ────
def test_invoke_maps_missing_default_model_to_400(monkeypatch):
def test_invoke_maps_missing_default_model_to_400(monkeypatch: pytest.MonkeyPatch):
import services.agent.skill_tool_inference_service as module
from core.errors.error import ProviderTokenNotInitError
@ -140,7 +140,7 @@ def test_invoke_maps_missing_default_model_to_400(monkeypatch):
assert exc_info.value.status_code == 400
def test_invoke_maps_model_failure_to_422_and_success_returns_text(monkeypatch):
def test_invoke_maps_model_failure_to_422_and_success_returns_text(monkeypatch: pytest.MonkeyPatch):
import services.agent.skill_tool_inference_service as module
fake_manager = MagicMock()
@ -173,7 +173,7 @@ def test_load_skill_md_passes_through_non_missing_drive_errors():
assert exc_info.value.code == "agent_not_found"
def _patch_inference_db(monkeypatch, *, agent, snapshot):
def _patch_inference_db(monkeypatch: pytest.MonkeyPatch, *, agent, snapshot):
from types import SimpleNamespace
import services.agent.skill_tool_inference_service as module
@ -182,7 +182,7 @@ def _patch_inference_db(monkeypatch, *, agent, snapshot):
monkeypatch.setattr(module.db, "session", SimpleNamespace(scalar=lambda stmt: next(results)))
def test_manifest_files_from_soul_reads_active_snapshot(monkeypatch):
def test_manifest_files_from_soul_reads_active_snapshot(monkeypatch: pytest.MonkeyPatch):
from types import SimpleNamespace
soul_dict = {
@ -203,7 +203,7 @@ def test_manifest_files_from_soul_reads_active_snapshot(monkeypatch):
assert files == ["scripts/a.sh"]
def test_manifest_files_from_soul_degrades_when_agent_or_snapshot_missing(monkeypatch):
def test_manifest_files_from_soul_degrades_when_agent_or_snapshot_missing(monkeypatch: pytest.MonkeyPatch):
_patch_inference_db(monkeypatch, agent=None, snapshot=None)
assert SkillToolInferenceService._manifest_files_from_soul(tenant_id="t", agent_id="a", slug="s") == []
@ -213,7 +213,7 @@ def test_manifest_files_from_soul_degrades_when_agent_or_snapshot_missing(monkey
assert SkillToolInferenceService._manifest_files_from_soul(tenant_id="t", agent_id="a", slug="s") == []
def test_manifest_files_from_soul_empty_when_slug_not_in_soul(monkeypatch):
def test_manifest_files_from_soul_empty_when_slug_not_in_soul(monkeypatch: pytest.MonkeyPatch):
from types import SimpleNamespace
soul_dict = {"skills_files": {"skills": [{"name": "Other", "skill_md_key": "other/SKILL.md"}]}}

View File

@ -385,7 +385,7 @@ def test_workflow_tool_import_publishes_referenced_app_before_create(monkeypatch
(IdStrategy.GENERATE_NEW_ID, ""),
],
)
def test_workflow_tool_import_id_follows_id_strategy(monkeypatch, id_strategy, expected_import_id):
def test_workflow_tool_import_id_follows_id_strategy(monkeypatch: pytest.MonkeyPatch, id_strategy, expected_import_id):
created_kwargs = []
target_provider = type("WorkflowToolProvider", (), {"id": "target-workflow-tool-id"})()
account = type("Account", (), {"id": "account-1"})()

View File

@ -1,3 +1,5 @@
from pytest_mock import MockerFixture
from services.rag_pipeline.pipeline_template.built_in.built_in_retrieval import BuiltInPipelineTemplateRetrieval
from services.rag_pipeline.pipeline_template.pipeline_template_type import PipelineTemplateType
@ -8,7 +10,7 @@ def test_get_type() -> None:
assert retrieval.get_type() == PipelineTemplateType.BUILTIN
def test_get_pipeline_templates(mocker) -> None:
def test_get_pipeline_templates(mocker: MockerFixture) -> None:
mocker.patch.object(
BuiltInPipelineTemplateRetrieval,
"_get_builtin_data",
@ -26,7 +28,7 @@ def test_get_pipeline_templates(mocker) -> None:
assert templates == {"pipeline_templates": [{"id": "tpl-1"}]}
def test_get_pipeline_template_detail(mocker) -> None:
def test_get_pipeline_template_detail(mocker: MockerFixture) -> None:
mocker.patch.object(
BuiltInPipelineTemplateRetrieval,
"_get_builtin_data",
@ -43,7 +45,7 @@ def test_get_pipeline_template_detail(mocker) -> None:
assert detail == {"id": "tpl-1", "name": "Template 1"}
def test_get_pipeline_templates_missing_language_returns_empty_dict(mocker) -> None:
def test_get_pipeline_templates_missing_language_returns_empty_dict(mocker: MockerFixture) -> None:
mocker.patch.object(
BuiltInPipelineTemplateRetrieval,
"_get_builtin_data",
@ -56,7 +58,7 @@ def test_get_pipeline_templates_missing_language_returns_empty_dict(mocker) -> N
assert result == {}
def test_get_pipeline_template_detail_returns_none_for_unknown_id(mocker) -> None:
def test_get_pipeline_template_detail_returns_none_for_unknown_id(mocker: MockerFixture) -> None:
mocker.patch.object(
BuiltInPipelineTemplateRetrieval,
"_get_builtin_data",
@ -69,7 +71,7 @@ def test_get_pipeline_template_detail_returns_none_for_unknown_id(mocker) -> Non
assert result is None
def test_get_builtin_data_reads_from_file_and_caches(mocker) -> None:
def test_get_builtin_data_reads_from_file_and_caches(mocker: MockerFixture) -> None:
import json
# Ensure no cached data
@ -98,7 +100,7 @@ def test_get_builtin_data_reads_from_file_and_caches(mocker) -> None:
BuiltInPipelineTemplateRetrieval.builtin_data = None
def test_get_builtin_data_returns_cache_on_second_call(mocker) -> None:
def test_get_builtin_data_returns_cache_on_second_call(mocker: MockerFixture) -> None:
cached_data = {"pipeline_templates": {"en-US": {}}}
BuiltInPipelineTemplateRetrieval.builtin_data = cached_data

View File

@ -1,10 +1,12 @@
from types import SimpleNamespace
from pytest_mock import MockerFixture
from services.rag_pipeline.pipeline_template.customized.customized_retrieval import CustomizedPipelineTemplateRetrieval
from services.rag_pipeline.pipeline_template.pipeline_template_type import PipelineTemplateType
def test_get_pipeline_templates(mocker) -> None:
def test_get_pipeline_templates(mocker: MockerFixture) -> None:
customized_template = SimpleNamespace(
id="tpl-1",
name="Custom Template",
@ -40,7 +42,7 @@ def test_get_pipeline_templates(mocker) -> None:
}
def test_get_pipeline_template_detail_returns_detail(mocker) -> None:
def test_get_pipeline_template_detail_returns_detail(mocker: MockerFixture) -> None:
session_mock = mocker.Mock()
session_mock.get.return_value = SimpleNamespace(
id="tpl-1",
@ -71,7 +73,7 @@ def test_get_pipeline_template_detail_returns_detail(mocker) -> None:
}
def test_get_pipeline_template_detail_returns_none_when_not_found(mocker) -> None:
def test_get_pipeline_template_detail_returns_none_when_not_found(mocker: MockerFixture) -> None:
session_mock = mocker.Mock()
session_mock.get.return_value = None
mocker.patch(

View File

@ -1,10 +1,12 @@
from types import SimpleNamespace
from pytest_mock import MockerFixture
from services.rag_pipeline.pipeline_template.database.database_retrieval import DatabasePipelineTemplateRetrieval
from services.rag_pipeline.pipeline_template.pipeline_template_type import PipelineTemplateType
def test_get_pipeline_templates(mocker) -> None:
def test_get_pipeline_templates(mocker: MockerFixture) -> None:
built_in_template = SimpleNamespace(
id="tpl-1",
name="Template 1",
@ -44,7 +46,7 @@ def test_get_pipeline_templates(mocker) -> None:
}
def test_get_pipeline_template_detail_returns_detail(mocker) -> None:
def test_get_pipeline_template_detail_returns_detail(mocker: MockerFixture) -> None:
session_mock = mocker.Mock()
session_mock.get.return_value = SimpleNamespace(
id="tpl-1",
@ -73,7 +75,7 @@ def test_get_pipeline_template_detail_returns_detail(mocker) -> None:
}
def test_get_pipeline_template_detail_returns_none_when_not_found(mocker) -> None:
def test_get_pipeline_template_detail_returns_none_when_not_found(mocker: MockerFixture) -> None:
session_mock = mocker.Mock()
session_mock.get.return_value = None
mocker.patch(

View File

@ -1,11 +1,12 @@
import pytest
from pytest_mock import MockerFixture
from services.rag_pipeline.pipeline_template.database.database_retrieval import DatabasePipelineTemplateRetrieval
from services.rag_pipeline.pipeline_template.pipeline_template_type import PipelineTemplateType
from services.rag_pipeline.pipeline_template.remote.remote_retrieval import RemotePipelineTemplateRetrieval
def test_get_pipeline_templates_fallbacks_to_database_on_error(mocker) -> None:
def test_get_pipeline_templates_fallbacks_to_database_on_error(mocker: MockerFixture) -> None:
fetch_mock = mocker.patch.object(
RemotePipelineTemplateRetrieval,
"fetch_pipeline_templates_from_dify_official",
@ -26,7 +27,7 @@ def test_get_pipeline_templates_fallbacks_to_database_on_error(mocker) -> None:
fallback_mock.assert_called_once_with("en-US")
def test_get_pipeline_template_detail_fallbacks_to_database_on_error(mocker) -> None:
def test_get_pipeline_template_detail_fallbacks_to_database_on_error(mocker: MockerFixture) -> None:
fetch_mock = mocker.patch.object(
RemotePipelineTemplateRetrieval,
"fetch_pipeline_template_detail_from_dify_official",
@ -46,7 +47,7 @@ def test_get_pipeline_template_detail_fallbacks_to_database_on_error(mocker) ->
fallback_mock.assert_called_once_with("tpl-1")
def test_fetch_pipeline_templates_from_dify_official(mocker) -> None:
def test_fetch_pipeline_templates_from_dify_official(mocker: MockerFixture) -> None:
mocker.patch(
"services.rag_pipeline.pipeline_template.remote.remote_retrieval"
".dify_config.HOSTED_FETCH_PIPELINE_TEMPLATES_REMOTE_DOMAIN",
@ -72,7 +73,7 @@ def test_fetch_pipeline_templates_from_dify_official(mocker) -> None:
assert http_get_mock.call_count == 2
def test_fetch_pipeline_template_detail_from_dify_official(mocker) -> None:
def test_fetch_pipeline_template_detail_from_dify_official(mocker: MockerFixture) -> None:
mocker.patch(
"services.rag_pipeline.pipeline_template.remote.remote_retrieval"
".dify_config.HOSTED_FETCH_PIPELINE_TEMPLATES_REMOTE_DOMAIN",

View File

@ -2,6 +2,7 @@ from types import SimpleNamespace
from typing import cast
import pytest
from pytest_mock import MockerFixture
from core.app.entities.app_invoke_entities import InvokeFrom
from models.dataset import Pipeline
@ -9,7 +10,7 @@ from models.model import Account, App, EndUser
from services.rag_pipeline.pipeline_generate_service import PipelineGenerateService
def test_get_max_active_requests_uses_smallest_non_zero_limit(mocker) -> None:
def test_get_max_active_requests_uses_smallest_non_zero_limit(mocker: MockerFixture) -> None:
mocker.patch("services.rag_pipeline.pipeline_generate_service.dify_config.APP_DEFAULT_ACTIVE_REQUESTS", 5)
mocker.patch("services.rag_pipeline.pipeline_generate_service.dify_config.APP_MAX_ACTIVE_REQUESTS", 3)
@ -20,7 +21,7 @@ def test_get_max_active_requests_uses_smallest_non_zero_limit(mocker) -> None:
assert result == 3
def test_get_max_active_requests_returns_zero_when_all_unlimited(mocker) -> None:
def test_get_max_active_requests_returns_zero_when_all_unlimited(mocker: MockerFixture) -> None:
mocker.patch("services.rag_pipeline.pipeline_generate_service.dify_config.APP_DEFAULT_ACTIVE_REQUESTS", 0)
mocker.patch("services.rag_pipeline.pipeline_generate_service.dify_config.APP_MAX_ACTIVE_REQUESTS", 0)
@ -39,7 +40,7 @@ def test_get_max_active_requests_returns_zero_when_all_unlimited(mocker) -> None
(InvokeFrom.DEBUGGER, SimpleNamespace(id="wf-1"), None),
],
)
def test_get_workflow(mocker, invoke_from, workflow, expected_error) -> None:
def test_get_workflow(mocker: MockerFixture, invoke_from, workflow, expected_error) -> None:
rag_pipeline_service_cls = mocker.patch("services.rag_pipeline.pipeline_generate_service.RagPipelineService")
rag_pipeline_service = rag_pipeline_service_cls.return_value
rag_pipeline_service.get_draft_workflow.return_value = workflow
@ -55,7 +56,7 @@ def test_get_workflow(mocker, invoke_from, workflow, expected_error) -> None:
assert result == workflow
def test_generate_updates_document_status_and_returns_event_stream(mocker) -> None:
def test_generate_updates_document_status_and_returns_event_stream(mocker: MockerFixture) -> None:
pipeline = cast(Pipeline, SimpleNamespace(id="pipeline-1"))
user = cast(Account | EndUser, SimpleNamespace(id="user-1"))
args = {"original_document_id": "doc-1", "query": "hello"}
@ -80,7 +81,7 @@ def test_generate_updates_document_status_and_returns_event_stream(mocker) -> No
update_status_mock.assert_called_once_with("doc-1")
def test_update_document_status_updates_existing_document(mocker) -> None:
def test_update_document_status_updates_existing_document(mocker: MockerFixture) -> None:
document = SimpleNamespace(indexing_status="completed")
session_mock = mocker.Mock()
@ -99,7 +100,7 @@ def test_update_document_status_updates_existing_document(mocker) -> None:
commit_mock.assert_called_once()
def test_update_document_status_skips_when_document_missing(mocker) -> None:
def test_update_document_status_skips_when_document_missing(mocker: MockerFixture) -> None:
session_mock = mocker.Mock()
session_mock.get.return_value = None
add_mock = session_mock.add
@ -118,7 +119,7 @@ def test_update_document_status_skips_when_document_missing(mocker) -> None:
# --- generate_single_iteration ---
def test_generate_single_iteration_delegates(mocker) -> None:
def test_generate_single_iteration_delegates(mocker: MockerFixture) -> None:
mocker.patch.object(PipelineGenerateService, "_get_workflow", return_value=SimpleNamespace(id="wf-1"))
generator_cls = mocker.patch("services.rag_pipeline.pipeline_generate_service.PipelineGenerator")
@ -138,7 +139,7 @@ def test_generate_single_iteration_delegates(mocker) -> None:
# --- generate_single_loop ---
def test_generate_single_loop_delegates(mocker) -> None:
def test_generate_single_loop_delegates(mocker: MockerFixture) -> None:
mocker.patch.object(PipelineGenerateService, "_get_workflow", return_value=SimpleNamespace(id="wf-1"))
generator_cls = mocker.patch("services.rag_pipeline.pipeline_generate_service.PipelineGenerator")

View File

@ -4,6 +4,7 @@ from unittest.mock import MagicMock, Mock
import pytest
import yaml
from pytest_mock import MockerFixture
from sqlalchemy.orm import Session
from core.workflow.nodes.knowledge_index import KNOWLEDGE_INDEX_NODE_TYPE
@ -55,7 +56,7 @@ def test_get_leaked_dependencies_returns_empty_list_for_empty_input() -> None:
assert result == []
def test_get_leaked_dependencies_delegates_to_analysis_service(mocker) -> None:
def test_get_leaked_dependencies_delegates_to_analysis_service(mocker: MockerFixture) -> None:
expected = [Mock()]
get_leaked_mock = mocker.patch(
"services.rag_pipeline.rag_pipeline_dsl_service.DependenciesAnalysisService.get_leaked_dependencies",
@ -72,7 +73,7 @@ def test_get_leaked_dependencies_delegates_to_analysis_service(mocker) -> None:
# --- check_dependencies ---
def test_check_dependencies_returns_empty_when_no_redis_data(mocker) -> None:
def test_check_dependencies_returns_empty_when_no_redis_data(mocker: MockerFixture) -> None:
mocker.patch(
"services.rag_pipeline.rag_pipeline_dsl_service.redis_client.get",
return_value=None,
@ -85,7 +86,7 @@ def test_check_dependencies_returns_empty_when_no_redis_data(mocker) -> None:
assert result.leaked_dependencies == []
def test_check_dependencies_returns_leaked_deps_from_redis(mocker) -> None:
def test_check_dependencies_returns_leaked_deps_from_redis(mocker: MockerFixture) -> None:
from core.plugin.entities.plugin import PluginDependency
from services.rag_pipeline.rag_pipeline_dsl_service import CheckDependenciesPendingData
@ -117,7 +118,7 @@ def test_check_dependencies_returns_leaked_deps_from_redis(mocker) -> None:
# --- _extract_dependencies_from_model_config ---
def test_extract_dependencies_from_model_config_extracts_model(mocker) -> None:
def test_extract_dependencies_from_model_config_extracts_model(mocker: MockerFixture) -> None:
analyze_mock = mocker.patch(
"services.rag_pipeline.rag_pipeline_dsl_service.DependenciesAnalysisService.analyze_model_provider_dependency",
return_value="langgenius/openai",
@ -130,7 +131,7 @@ def test_extract_dependencies_from_model_config_extracts_model(mocker) -> None:
analyze_mock.assert_called_with("openai")
def test_extract_dependencies_from_model_config_extracts_tools(mocker) -> None:
def test_extract_dependencies_from_model_config_extracts_tools(mocker: MockerFixture) -> None:
mocker.patch(
"services.rag_pipeline.rag_pipeline_dsl_service.DependenciesAnalysisService.analyze_model_provider_dependency",
return_value="x",
@ -159,7 +160,7 @@ def test_extract_dependencies_from_model_config_empty_config() -> None:
# --- _extract_dependencies_from_workflow_graph ---
def test_extract_dependencies_from_workflow_graph_ignores_unknown_types(mocker) -> None:
def test_extract_dependencies_from_workflow_graph_ignores_unknown_types(mocker: MockerFixture) -> None:
service = RagPipelineDslService(session=Mock())
graph = {"nodes": [{"data": {"type": "some-unknown-type"}}]}
@ -176,7 +177,7 @@ def test_extract_dependencies_from_workflow_graph_handles_empty_graph() -> None:
assert result == []
def test_extract_dependencies_from_workflow_graph_handles_malformed_node(mocker) -> None:
def test_extract_dependencies_from_workflow_graph_handles_malformed_node(mocker: MockerFixture) -> None:
service = RagPipelineDslService(session=Mock())
# Node with TOOL type but invalid data should be caught by exception handler
from graphon.enums import BuiltinNodeTypes
@ -205,7 +206,7 @@ def test_export_rag_pipeline_dsl_raises_when_dataset_missing() -> None:
# --- import_rag_pipeline ---
def test_import_rag_pipeline_url_fetch_error(mocker) -> None:
def test_import_rag_pipeline_url_fetch_error(mocker: MockerFixture) -> None:
mocker.patch(
"services.rag_pipeline.rag_pipeline_dsl_service.remote_fetcher.make_request",
side_effect=Exception("fetch failed"),
@ -221,7 +222,7 @@ def test_import_rag_pipeline_url_fetch_error(mocker) -> None:
assert "fetch failed" in result.error
def test_import_rag_pipeline_yaml_content_success(mocker) -> None:
def test_import_rag_pipeline_yaml_content_success(mocker: MockerFixture) -> None:
yaml_content = """
version: 0.1.0
kind: rag_pipeline
@ -269,7 +270,7 @@ workflow:
session.flush.assert_called()
def test_import_rag_pipeline_flushes_new_collection_binding_without_commit(mocker) -> None:
def test_import_rag_pipeline_flushes_new_collection_binding_without_commit(mocker: MockerFixture) -> None:
yaml_content = """
version: 0.1.0
kind: rag_pipeline
@ -321,7 +322,7 @@ workflow:
assert session.flush.call_count >= 2
def test_import_rag_pipeline_pending_version(mocker) -> None:
def test_import_rag_pipeline_pending_version(mocker: MockerFixture) -> None:
yaml_content = "version: 1.0.0\nkind: rag_pipeline\nrag_pipeline: {name: x}"
mocker.patch("services.rag_pipeline.rag_pipeline_dsl_service.redis_client.setex")
service = RagPipelineDslService(session=Mock())
@ -336,7 +337,7 @@ def test_import_rag_pipeline_pending_version(mocker) -> None:
# --- confirm_import ---
def test_confirm_import_success(mocker) -> None:
def test_confirm_import_success(mocker: MockerFixture) -> None:
from services.rag_pipeline.rag_pipeline_dsl_service import RagPipelinePendingData
yaml_content = """
@ -398,7 +399,7 @@ workflow:
assert result.dataset_id == "d1"
def test_confirm_import_flushes_new_collection_binding_without_commit(mocker) -> None:
def test_confirm_import_flushes_new_collection_binding_without_commit(mocker: MockerFixture) -> None:
from services.rag_pipeline.rag_pipeline_dsl_service import RagPipelinePendingData
yaml_content = """
@ -518,7 +519,7 @@ def test_extract_dependencies_from_workflow_graph_types(mocker, node_type) -> No
# --- _create_or_update_pipeline ---
def test_create_or_update_pipeline_create_new(mocker) -> None:
def test_create_or_update_pipeline_create_new(mocker: MockerFixture) -> None:
session = cast(MagicMock, Mock())
service = RagPipelineDslService(session=cast(Session, session))
account = Mock(current_tenant_id="t1", id="u1")
@ -549,7 +550,7 @@ def test_create_or_update_pipeline_create_new(mocker) -> None:
# --- export_rag_pipeline_dsl comprehensive ---
def test_export_rag_pipeline_dsl_with_workflow(mocker) -> None:
def test_export_rag_pipeline_dsl_with_workflow(mocker: MockerFixture) -> None:
session = cast(MagicMock, Mock())
service = RagPipelineDslService(session=cast(Session, session))
pipeline = Mock()
@ -591,7 +592,7 @@ def test_export_rag_pipeline_dsl_with_workflow(mocker) -> None:
# --- _extract_dependencies_from_workflow_graph more types ---
def test_extract_dependencies_from_workflow_graph_datasource(mocker) -> None:
def test_extract_dependencies_from_workflow_graph_datasource(mocker: MockerFixture) -> None:
mocker.patch(
"services.rag_pipeline.rag_pipeline_dsl_service.DatasourceNodeData.model_validate",
return_value=Mock(provider_type="online", plugin_id="ds1"),
@ -642,7 +643,7 @@ def test_import_rag_pipeline_yaml_content_requires_mapping() -> None:
assert "content must be a mapping" in result.error
def test_confirm_import_returns_failed_when_pending_data_is_invalid_type(mocker) -> None:
def test_confirm_import_returns_failed_when_pending_data_is_invalid_type(mocker: MockerFixture) -> None:
mocker.patch("services.rag_pipeline.rag_pipeline_dsl_service.redis_client.get", return_value=object())
service = RagPipelineDslService(session=Mock())
account = Mock(current_tenant_id="t1")
@ -653,7 +654,7 @@ def test_confirm_import_returns_failed_when_pending_data_is_invalid_type(mocker)
assert "Invalid import information" in result.error
def test_append_workflow_export_data_filters_credentials(mocker) -> None:
def test_append_workflow_export_data_filters_credentials(mocker: MockerFixture) -> None:
session = cast(MagicMock, Mock())
service = RagPipelineDslService(session=cast(Session, session))
workflow = Mock()
@ -691,7 +692,7 @@ def test_append_workflow_export_data_filters_credentials(mocker) -> None:
assert "credential_id" not in nodes[1]["data"]["agent_parameters"]["tools"]["value"][0]
def test_create_rag_pipeline_dataset_raises_when_name_conflicts(mocker) -> None:
def test_create_rag_pipeline_dataset_raises_when_name_conflicts(mocker: MockerFixture) -> None:
session = cast(MagicMock, Mock())
service = RagPipelineDslService(session=cast(Session, session))
session.scalar.return_value = Mock()
@ -707,7 +708,7 @@ def test_create_rag_pipeline_dataset_raises_when_name_conflicts(mocker) -> None:
service.create_rag_pipeline_dataset("tenant-1", create_entity)
def test_create_rag_pipeline_dataset_generates_name_when_missing(mocker) -> None:
def test_create_rag_pipeline_dataset_generates_name_when_missing(mocker: MockerFixture) -> None:
session = cast(MagicMock, Mock())
service = RagPipelineDslService(session=cast(Session, session))
session.scalar.return_value = None
@ -741,7 +742,7 @@ def test_create_rag_pipeline_dataset_generates_name_when_missing(mocker) -> None
assert result["status"] == ImportStatus.COMPLETED
def test_append_workflow_export_data_encrypts_knowledge_retrieval_dataset_ids(mocker) -> None:
def test_append_workflow_export_data_encrypts_knowledge_retrieval_dataset_ids(mocker: MockerFixture) -> None:
session = cast(MagicMock, Mock())
service = RagPipelineDslService(session=cast(Session, session))
workflow = Mock()
@ -773,7 +774,7 @@ def test_append_workflow_export_data_encrypts_knowledge_retrieval_dataset_ids(mo
assert ids == ["enc-d1", "enc-d2"]
def test_confirm_import_updates_existing_dataset(mocker) -> None:
def test_confirm_import_updates_existing_dataset(mocker: MockerFixture) -> None:
from services.rag_pipeline.rag_pipeline_dsl_service import RagPipelinePendingData
yaml_content = (
@ -812,7 +813,7 @@ def test_confirm_import_updates_existing_dataset(mocker) -> None:
assert dataset.indexing_technique == "economy"
def test_import_rag_pipeline_yaml_url_handles_empty_content_after_github_rewrite(mocker) -> None:
def test_import_rag_pipeline_yaml_url_handles_empty_content_after_github_rewrite(mocker: MockerFixture) -> None:
response = Mock()
response.raise_for_status.return_value = None
response.content = b""
@ -835,7 +836,7 @@ def test_import_rag_pipeline_yaml_url_handles_empty_content_after_github_rewrite
assert "raw.githubusercontent.com" in called_url
def test_create_or_update_pipeline_decrypts_knowledge_retrieval_dataset_ids(mocker) -> None:
def test_create_or_update_pipeline_decrypts_knowledge_retrieval_dataset_ids(mocker: MockerFixture) -> None:
session = cast(MagicMock, Mock())
service = RagPipelineDslService(session=cast(Session, session))
account = Mock(id="u1", current_tenant_id="t1")
@ -866,7 +867,7 @@ def test_create_or_update_pipeline_decrypts_knowledge_retrieval_dataset_ids(mock
assert draft_workflow.graph is not None
def test_create_or_update_pipeline_creates_draft_when_missing(mocker) -> None:
def test_create_or_update_pipeline_creates_draft_when_missing(mocker: MockerFixture) -> None:
session = cast(MagicMock, Mock())
service = RagPipelineDslService(session=cast(Session, session))
account = Mock(id="u1", current_tenant_id="t1")
@ -882,7 +883,7 @@ def test_create_or_update_pipeline_creates_draft_when_missing(mocker) -> None:
assert pipeline.workflow_id == "wf-new"
def test_import_rag_pipeline_url_size_exceeds_limit(mocker) -> None:
def test_import_rag_pipeline_url_size_exceeds_limit(mocker: MockerFixture) -> None:
response = Mock()
response.raise_for_status.return_value = None
response.content = b"x" * (10 * 1024 * 1024 + 1)
@ -953,7 +954,7 @@ def test_append_workflow_export_data_raises_when_draft_workflow_missing() -> Non
service._append_workflow_export_data(export_data={}, pipeline=Mock(tenant_id="t1"), include_secret=False)
def test_append_workflow_export_data_keeps_secret_fields_when_include_secret_true(mocker) -> None:
def test_append_workflow_export_data_keeps_secret_fields_when_include_secret_true(mocker: MockerFixture) -> None:
session = cast(MagicMock, Mock())
service = RagPipelineDslService(session=cast(Session, session))
workflow = Mock()
@ -992,7 +993,7 @@ def test_append_workflow_export_data_keeps_secret_fields_when_include_secret_tru
assert tool_values[0]["credential_id"] == "agent-secret"
def test_extract_dependencies_from_workflow_graph_skips_local_file_datasource(mocker) -> None:
def test_extract_dependencies_from_workflow_graph_skips_local_file_datasource(mocker: MockerFixture) -> None:
mocker.patch(
"services.rag_pipeline.rag_pipeline_dsl_service.DatasourceNodeData.model_validate",
return_value=Mock(provider_type="local_file", plugin_id="plugin-x"),
@ -1006,7 +1007,7 @@ def test_extract_dependencies_from_workflow_graph_skips_local_file_datasource(mo
assert result == []
def test_extract_dependencies_from_workflow_graph_knowledge_index_reranking(mocker) -> None:
def test_extract_dependencies_from_workflow_graph_knowledge_index_reranking(mocker: MockerFixture) -> None:
analyze = mocker.patch(
"services.rag_pipeline.rag_pipeline_dsl_service.DependenciesAnalysisService.analyze_model_provider_dependency",
side_effect=lambda provider: f"dep:{provider}",
@ -1031,7 +1032,7 @@ def test_extract_dependencies_from_workflow_graph_knowledge_index_reranking(mock
assert analyze.call_count == 2
def test_extract_dependencies_from_workflow_graph_multiple_retrieval_weighted_score(mocker) -> None:
def test_extract_dependencies_from_workflow_graph_multiple_retrieval_weighted_score(mocker: MockerFixture) -> None:
mocker.patch(
"services.rag_pipeline.rag_pipeline_dsl_service.DependenciesAnalysisService.analyze_model_provider_dependency",
return_value="dep:weighted",
@ -1053,7 +1054,7 @@ def test_extract_dependencies_from_workflow_graph_multiple_retrieval_weighted_sc
assert result == ["dep:weighted"]
def test_extract_dependencies_from_workflow_graph_multiple_retrieval_reranking_model(mocker) -> None:
def test_extract_dependencies_from_workflow_graph_multiple_retrieval_reranking_model(mocker: MockerFixture) -> None:
mocker.patch(
"services.rag_pipeline.rag_pipeline_dsl_service.DependenciesAnalysisService.analyze_model_provider_dependency",
return_value="dep:rerank",
@ -1075,7 +1076,7 @@ def test_extract_dependencies_from_workflow_graph_multiple_retrieval_reranking_m
assert result == ["dep:rerank"]
def test_extract_dependencies_from_model_config_includes_dataset_reranking_and_tools(mocker) -> None:
def test_extract_dependencies_from_model_config_includes_dataset_reranking_and_tools(mocker: MockerFixture) -> None:
model_analyze = mocker.patch(
"services.rag_pipeline.rag_pipeline_dsl_service.DependenciesAnalysisService.analyze_model_provider_dependency",
side_effect=["dep:model", "dep:rerank"],
@ -1107,7 +1108,7 @@ def test_extract_dependencies_from_model_config_includes_dataset_reranking_and_t
tool_analyze.assert_called_once_with("google")
def test_check_version_compatibility_hits_major_older_branch(mocker) -> None:
def test_check_version_compatibility_hits_major_older_branch(mocker: MockerFixture) -> None:
mocker.patch("services.rag_pipeline.rag_pipeline_dsl_service.CURRENT_DSL_VERSION", "1.0.0")
status = check_version_compatibility("0.9.0", rag_pipeline_dsl_service.CURRENT_DSL_VERSION)
@ -1115,7 +1116,7 @@ def test_check_version_compatibility_hits_major_older_branch(mocker) -> None:
assert status == ImportStatus.PENDING
def test_import_rag_pipeline_sets_default_version_and_kind(mocker) -> None:
def test_import_rag_pipeline_sets_default_version_and_kind(mocker: MockerFixture) -> None:
session = cast(MagicMock, Mock())
service = RagPipelineDslService(session=cast(Session, session))
account = Mock(current_tenant_id="t1")
@ -1147,7 +1148,7 @@ def test_import_rag_pipeline_sets_default_version_and_kind(mocker) -> None:
assert result.imported_dsl_version == "0.1.0"
def test_import_rag_pipeline_creates_pending_for_dependencies(mocker) -> None:
def test_import_rag_pipeline_creates_pending_for_dependencies(mocker: MockerFixture) -> None:
session = cast(MagicMock, Mock())
service = RagPipelineDslService(session=cast(Session, session))
account = Mock(current_tenant_id="t1")
@ -1169,7 +1170,7 @@ workflow: {graph: {nodes: []}}
setex.assert_called_once()
def test_confirm_import_returns_failed_when_pending_pipeline_missing(mocker) -> None:
def test_confirm_import_returns_failed_when_pending_pipeline_missing(mocker: MockerFixture) -> None:
from services.rag_pipeline.rag_pipeline_dsl_service import RagPipelinePendingData
pending = RagPipelinePendingData(import_mode="yaml-content", yaml_content="version: 0.1.0", pipeline_id="p1")
@ -1186,7 +1187,7 @@ def test_confirm_import_returns_failed_when_pending_pipeline_missing(mocker) ->
assert result.status == ImportStatus.FAILED
def test_append_workflow_export_data_skips_empty_node_data(mocker) -> None:
def test_append_workflow_export_data_skips_empty_node_data(mocker: MockerFixture) -> None:
session = cast(MagicMock, Mock())
service = RagPipelineDslService(session=cast(Session, session))
workflow = Mock()
@ -1204,7 +1205,7 @@ def test_append_workflow_export_data_skips_empty_node_data(mocker) -> None:
assert "workflow" in export_data
def test_extract_dependencies_from_workflow_graph_multiple_config_none(mocker) -> None:
def test_extract_dependencies_from_workflow_graph_multiple_config_none(mocker: MockerFixture) -> None:
retrieval = Mock()
retrieval.retrieval_mode = "multiple"
retrieval.multiple_retrieval_config = None
@ -1221,7 +1222,7 @@ def test_extract_dependencies_from_workflow_graph_multiple_config_none(mocker) -
assert result == []
def test_extract_dependencies_from_workflow_graph_single_config_none(mocker) -> None:
def test_extract_dependencies_from_workflow_graph_single_config_none(mocker: MockerFixture) -> None:
retrieval = Mock()
retrieval.retrieval_mode = "single"
retrieval.single_retrieval_config = None
@ -1246,7 +1247,7 @@ def test_create_or_update_pipeline_raises_when_workflow_missing() -> None:
service._create_or_update_pipeline(pipeline=None, data={"rag_pipeline": {"name": "x"}}, account=account)
def test_import_rag_pipeline_with_pipeline_id_uses_existing_dataset(mocker) -> None:
def test_import_rag_pipeline_with_pipeline_id_uses_existing_dataset(mocker: MockerFixture) -> None:
session = cast(MagicMock, Mock())
service = RagPipelineDslService(session=cast(Session, session))
existing_dataset = Mock(id="d1", chunk_structure="text_model")
@ -1282,7 +1283,7 @@ def test_import_rag_pipeline_with_pipeline_id_uses_existing_dataset(mocker) -> N
assert result.dataset_id == "d1"
def test_import_rag_pipeline_raises_for_chunk_structure_mismatch_on_published(mocker) -> None:
def test_import_rag_pipeline_raises_for_chunk_structure_mismatch_on_published(mocker: MockerFixture) -> None:
session = cast(MagicMock, Mock())
service = RagPipelineDslService(session=cast(Session, session))
existing_dataset = Mock(id="d1", chunk_structure="hierarchical_model")
@ -1318,7 +1319,7 @@ def test_import_rag_pipeline_raises_for_chunk_structure_mismatch_on_published(mo
assert "Chunk structure is not compatible" in result.error
def test_import_rag_pipeline_fails_when_no_knowledge_index_node(mocker) -> None:
def test_import_rag_pipeline_fails_when_no_knowledge_index_node(mocker: MockerFixture) -> None:
service = RagPipelineDslService(session=Mock())
pipeline = Mock(id="p1", name="P", description="D", is_published=False)
mocker.patch.object(service, "_create_or_update_pipeline", return_value=pipeline)
@ -1340,7 +1341,7 @@ def test_import_rag_pipeline_fails_when_no_knowledge_index_node(mocker) -> None:
assert "Knowledge Index node" in result.error
def test_confirm_import_fails_when_no_knowledge_index_node(mocker) -> None:
def test_confirm_import_fails_when_no_knowledge_index_node(mocker: MockerFixture) -> None:
from services.rag_pipeline.rag_pipeline_dsl_service import RagPipelinePendingData
yaml_content = (
@ -1369,7 +1370,7 @@ def test_confirm_import_fails_when_no_knowledge_index_node(mocker) -> None:
assert "Knowledge Index node" in result.error
def test_create_or_update_pipeline_saves_dependencies_to_redis(mocker) -> None:
def test_create_or_update_pipeline_saves_dependencies_to_redis(mocker: MockerFixture) -> None:
from core.plugin.entities.plugin import PluginDependency
session = cast(MagicMock, Mock())
@ -1399,7 +1400,9 @@ def test_create_or_update_pipeline_saves_dependencies_to_redis(mocker) -> None:
setex.assert_called_once()
def test_extract_dependencies_from_workflow_graph_knowledge_index_without_embedding_provider(mocker) -> None:
def test_extract_dependencies_from_workflow_graph_knowledge_index_without_embedding_provider(
mocker: MockerFixture,
) -> None:
mocker.patch(
"services.rag_pipeline.rag_pipeline_dsl_service.DependenciesAnalysisService.analyze_model_provider_dependency",
return_value="dep",
@ -1421,7 +1424,7 @@ def test_extract_dependencies_from_workflow_graph_knowledge_index_without_embedd
assert result == []
def test_extract_dependencies_from_workflow_graph_multiple_reranking_without_model(mocker) -> None:
def test_extract_dependencies_from_workflow_graph_multiple_reranking_without_model(mocker: MockerFixture) -> None:
retrieval = Mock()
retrieval.retrieval_mode = "multiple"
retrieval.multiple_retrieval_config.reranking_mode = "reranking_model"
@ -1439,7 +1442,7 @@ def test_extract_dependencies_from_workflow_graph_multiple_reranking_without_mod
assert result == []
def test_extract_dependencies_from_workflow_graph_multiple_weighted_without_weights(mocker) -> None:
def test_extract_dependencies_from_workflow_graph_multiple_weighted_without_weights(mocker: MockerFixture) -> None:
retrieval = Mock()
retrieval.retrieval_mode = "multiple"
retrieval.multiple_retrieval_config.reranking_mode = "weighted_score"

View File

@ -1,9 +1,11 @@
from types import SimpleNamespace
from pytest_mock import MockerFixture
from services.rag_pipeline.rag_pipeline_manage_service import RagPipelineManageService
def test_list_rag_pipeline_datasources_marks_authorized(mocker) -> None:
def test_list_rag_pipeline_datasources_marks_authorized(mocker: MockerFixture) -> None:
datasource_1 = SimpleNamespace(provider="notion", plugin_id="plugin-1", is_authorized=False)
datasource_2 = SimpleNamespace(provider="jina", plugin_id="plugin-2", is_authorized=False)

View File

@ -4,6 +4,7 @@ from datetime import datetime
from types import SimpleNamespace
import pytest
from pytest_mock import MockerFixture
from sqlalchemy.orm import sessionmaker
from models import Account, Tenant
@ -113,7 +114,7 @@ def _make_recommended_plugin(plugin_id: str) -> PipelineRecommendedPlugin:
return PipelineRecommendedPlugin(plugin_id=plugin_id, provider_name=plugin_id, type="tool", position=0, active=True)
def test_get_pipeline_templates_fallbacks_to_builtin_for_non_english_empty_result(mocker) -> None:
def test_get_pipeline_templates_fallbacks_to_builtin_for_non_english_empty_result(mocker: MockerFixture) -> None:
mocker.patch("services.rag_pipeline.rag_pipeline.dify_config.HOSTED_FETCH_PIPELINE_TEMPLATES_MODE", "remote")
remote_retrieval = mocker.Mock()
@ -132,7 +133,7 @@ def test_get_pipeline_templates_fallbacks_to_builtin_for_non_english_empty_resul
builtin_retrieval.fetch_pipeline_templates_from_builtin.assert_called_once_with("en-US")
def test_get_pipeline_templates_customized_mode_uses_customized_factory(mocker) -> None:
def test_get_pipeline_templates_customized_mode_uses_customized_factory(mocker: MockerFixture) -> None:
retrieval = mocker.Mock()
retrieval.get_pipeline_templates.return_value = {"pipeline_templates": [{"id": "custom-1"}]}
@ -146,7 +147,7 @@ def test_get_pipeline_templates_customized_mode_uses_customized_factory(mocker)
@pytest.mark.parametrize("template_type", ["built-in", "customized"])
def test_get_pipeline_template_detail_uses_expected_mode(mocker, template_type: str) -> None:
def test_get_pipeline_template_detail_uses_expected_mode(mocker: MockerFixture, template_type: str) -> None:
mocker.patch("services.rag_pipeline.rag_pipeline.dify_config.HOSTED_FETCH_PIPELINE_TEMPLATES_MODE", "remote")
retrieval = mocker.Mock()
retrieval.get_pipeline_template_detail.return_value = {"id": "tpl-1"}
@ -161,7 +162,9 @@ def test_get_pipeline_template_detail_uses_expected_mode(mocker, template_type:
factory_mock.get_pipeline_template_factory.assert_called_with(expected_mode)
def test_get_published_workflow_returns_none_when_pipeline_has_no_workflow_id(rag_pipeline_service) -> None:
def test_get_published_workflow_returns_none_when_pipeline_has_no_workflow_id(
rag_pipeline_service: RagPipelineService,
) -> None:
pipeline = _make_pipeline(workflow_id=None)
result = rag_pipeline_service.get_published_workflow(pipeline)
@ -169,7 +172,9 @@ def test_get_published_workflow_returns_none_when_pipeline_has_no_workflow_id(ra
assert result is None
def test_get_all_published_workflow_returns_empty_for_unpublished_pipeline(rag_pipeline_service) -> None:
def test_get_all_published_workflow_returns_empty_for_unpublished_pipeline(
rag_pipeline_service: RagPipelineService,
) -> None:
pipeline = _make_pipeline(workflow_id=None)
session = SimpleNamespace()
@ -186,7 +191,7 @@ def test_get_all_published_workflow_returns_empty_for_unpublished_pipeline(rag_p
assert has_more is False
def test_get_all_published_workflow_applies_limit_and_has_more(rag_pipeline_service) -> None:
def test_get_all_published_workflow_applies_limit_and_has_more(rag_pipeline_service: RagPipelineService) -> None:
scalars_result = SimpleNamespace(all=lambda: ["wf1", "wf2", "wf3"])
session = SimpleNamespace(scalars=lambda stmt: scalars_result)
pipeline = _make_pipeline(pipeline_id="pipeline-1", workflow_id="wf-live")
@ -207,7 +212,9 @@ def test_get_all_published_workflow_applies_limit_and_has_more(rag_pipeline_serv
# --- sync_draft_workflow ---
def test_sync_draft_workflow_creates_new_when_none_exists(mocker, rag_pipeline_service) -> None:
def test_sync_draft_workflow_creates_new_when_none_exists(
mocker: MockerFixture, rag_pipeline_service: RagPipelineService
) -> None:
mocker.patch.object(rag_pipeline_service, "get_draft_workflow", return_value=None)
class FakeWorkflow:
@ -238,7 +245,9 @@ def test_sync_draft_workflow_creates_new_when_none_exists(mocker, rag_pipeline_s
assert pipeline.workflow_id == "wf-new"
def test_sync_draft_workflow_raises_on_hash_mismatch(mocker, rag_pipeline_service) -> None:
def test_sync_draft_workflow_raises_on_hash_mismatch(
mocker: MockerFixture, rag_pipeline_service: RagPipelineService
) -> None:
from services.errors.app import WorkflowHashNotEqualError
existing_wf = _make_workflow(graph={"nodes": [{"id": "old"}]})
@ -259,7 +268,7 @@ def test_sync_draft_workflow_raises_on_hash_mismatch(mocker, rag_pipeline_servic
)
def test_sync_draft_workflow_updates_existing(mocker, rag_pipeline_service) -> None:
def test_sync_draft_workflow_updates_existing(mocker: MockerFixture, rag_pipeline_service: RagPipelineService) -> None:
existing_wf = SimpleNamespace(
unique_hash="hash-1",
graph=None,
@ -293,7 +302,9 @@ def test_sync_draft_workflow_updates_existing(mocker, rag_pipeline_service) -> N
# --- get_default_block_config ---
def test_get_default_block_config_returns_config_for_valid_type(mocker, rag_pipeline_service) -> None:
def test_get_default_block_config_returns_config_for_valid_type(
mocker: MockerFixture, rag_pipeline_service: RagPipelineService
) -> None:
fake_node_class = mocker.Mock()
fake_node_class.get_default_config.return_value = {"type": "start", "config": {}}
@ -311,14 +322,16 @@ def test_get_default_block_config_returns_config_for_valid_type(mocker, rag_pipe
assert result == {"type": "start", "config": {}}
def test_get_default_block_config_returns_none_for_unmapped_type(rag_pipeline_service) -> None:
def test_get_default_block_config_returns_none_for_unmapped_type(rag_pipeline_service: RagPipelineService) -> None:
assert rag_pipeline_service.get_default_block_config("nonexistent-type") is None
# --- update_workflow ---
def test_update_workflow_updates_allowed_fields(mocker, rag_pipeline_service) -> None:
def test_update_workflow_updates_allowed_fields(
mocker: MockerFixture, rag_pipeline_service: RagPipelineService
) -> None:
workflow = SimpleNamespace(
id="wf-1", marked_name="", marked_comment="", updated_by=None, updated_at=None, disallowed="original"
)
@ -339,7 +352,9 @@ def test_update_workflow_updates_allowed_fields(mocker, rag_pipeline_service) ->
assert result.updated_by == "u1"
def test_update_workflow_returns_none_when_not_found(mocker, rag_pipeline_service) -> None:
def test_update_workflow_returns_none_when_not_found(
mocker: MockerFixture, rag_pipeline_service: RagPipelineService
) -> None:
session = mocker.Mock()
session.scalar.return_value = None
@ -357,7 +372,9 @@ def test_update_workflow_returns_none_when_not_found(mocker, rag_pipeline_servic
# --- get_rag_pipeline_paginate_workflow_runs ---
def test_get_rag_pipeline_paginate_workflow_runs_delegates(mocker, rag_pipeline_service) -> None:
def test_get_rag_pipeline_paginate_workflow_runs_delegates(
mocker: MockerFixture, rag_pipeline_service: RagPipelineService
) -> None:
expected = mocker.Mock()
repo_mock = mocker.Mock()
repo_mock.get_paginated_workflow_runs.return_value = expected
@ -379,7 +396,9 @@ def test_get_rag_pipeline_paginate_workflow_runs_delegates(mocker, rag_pipeline_
# --- get_rag_pipeline_workflow_run ---
def test_get_rag_pipeline_workflow_run_delegates(mocker, rag_pipeline_service) -> None:
def test_get_rag_pipeline_workflow_run_delegates(
mocker: MockerFixture, rag_pipeline_service: RagPipelineService
) -> None:
expected = mocker.Mock()
repo_mock = mocker.Mock()
repo_mock.get_workflow_run_by_id.return_value = expected
@ -395,14 +414,18 @@ def test_get_rag_pipeline_workflow_run_delegates(mocker, rag_pipeline_service) -
# --- is_workflow_exist ---
def test_is_workflow_exist_returns_true_when_draft_exists(mocker, rag_pipeline_service) -> None:
def test_is_workflow_exist_returns_true_when_draft_exists(
mocker: MockerFixture, rag_pipeline_service: RagPipelineService
) -> None:
mocker.patch("services.rag_pipeline.rag_pipeline.db.session.scalar", return_value=1)
pipeline = _make_pipeline()
assert rag_pipeline_service.is_workflow_exist(pipeline) is True
def test_is_workflow_exist_returns_false_when_no_draft(mocker, rag_pipeline_service) -> None:
def test_is_workflow_exist_returns_false_when_no_draft(
mocker: MockerFixture, rag_pipeline_service: RagPipelineService
) -> None:
mocker.patch("services.rag_pipeline.rag_pipeline.db.session.scalar", return_value=0)
pipeline = _make_pipeline()
@ -412,7 +435,7 @@ def test_is_workflow_exist_returns_false_when_no_draft(mocker, rag_pipeline_serv
# --- publish_workflow ---
def test_publish_workflow_success(mocker, rag_pipeline_service) -> None:
def test_publish_workflow_success(mocker: MockerFixture, rag_pipeline_service: RagPipelineService) -> None:
# Don't import Workflow from rag_pipeline to avoid confusion during patching
# 1. Mock select to bypass SQLAlchemy validation
@ -483,7 +506,9 @@ def test_publish_workflow_success(mocker, rag_pipeline_service) -> None:
# --- run_datasource_workflow_node ---
def test_run_datasource_workflow_node_website_crawl(mocker, rag_pipeline_service) -> None:
def test_run_datasource_workflow_node_website_crawl(
mocker: MockerFixture, rag_pipeline_service: RagPipelineService
) -> None:
from core.datasource.entities.datasource_entities import DatasourceProviderType
# 1. Setup workflow and node
@ -559,7 +584,9 @@ def test_run_datasource_workflow_node_website_crawl(mocker, rag_pipeline_service
# --- run_datasource_node_preview ---
def test_run_datasource_node_preview_online_document(mocker, rag_pipeline_service) -> None:
def test_run_datasource_node_preview_online_document(
mocker: MockerFixture, rag_pipeline_service: RagPipelineService
) -> None:
from core.datasource.entities.datasource_entities import DatasourceMessage, DatasourceProviderType
# 1. Setup workflow and node
@ -632,7 +659,7 @@ def test_run_datasource_node_preview_online_document(mocker, rag_pipeline_servic
# --- _handle_node_run_result ---
def test_handle_node_run_result_success(mocker, rag_pipeline_service) -> None:
def test_handle_node_run_result_success(mocker: MockerFixture, rag_pipeline_service: RagPipelineService) -> None:
from graphon.enums import WorkflowNodeExecutionMetadataKey, WorkflowNodeExecutionStatus
from graphon.graph_events import NodeRunSucceededEvent
from graphon.node_events.base import NodeRunResult
@ -676,7 +703,7 @@ def test_handle_node_run_result_success(mocker, rag_pipeline_service) -> None:
# --- get_first_step_parameters / get_second_step_parameters ---
def test_get_first_step_parameters_success(mocker, rag_pipeline_service) -> None:
def test_get_first_step_parameters_success(mocker: MockerFixture, rag_pipeline_service: RagPipelineService) -> None:
# 1. Setup mock workflow
pipeline = mocker.Mock()
workflow = mocker.Mock()
@ -694,7 +721,7 @@ def test_get_first_step_parameters_success(mocker, rag_pipeline_service) -> None
assert result[0]["variable"] == "url"
def test_get_second_step_parameters_success(mocker, rag_pipeline_service) -> None:
def test_get_second_step_parameters_success(mocker: MockerFixture, rag_pipeline_service: RagPipelineService) -> None:
# 1. Setup mock workflow
pipeline = mocker.Mock()
workflow = mocker.Mock()
@ -722,7 +749,9 @@ def test_get_second_step_parameters_success(mocker, rag_pipeline_service) -> Non
# --- publish_customized_pipeline_template ---
def test_publish_customized_pipeline_template_success(mocker, rag_pipeline_service) -> None:
def test_publish_customized_pipeline_template_success(
mocker: MockerFixture, rag_pipeline_service: RagPipelineService
) -> None:
# 1. Setup mocks
pipeline = _make_pipeline(workflow_id="wf-1", is_published=True)
@ -765,7 +794,7 @@ def test_publish_customized_pipeline_template_success(mocker, rag_pipeline_servi
# --- get_datasource_plugins ---
def test_get_datasource_plugins_success(mocker, rag_pipeline_service) -> None:
def test_get_datasource_plugins_success(mocker: MockerFixture, rag_pipeline_service: RagPipelineService) -> None:
# 1. Setup mocks
dataset = _make_dataset()
@ -812,7 +841,7 @@ def test_get_datasource_plugins_success(mocker, rag_pipeline_service) -> None:
# --- retry_error_document ---
def test_retry_error_document_success(mocker, rag_pipeline_service) -> None:
def test_retry_error_document_success(mocker: MockerFixture, rag_pipeline_service: RagPipelineService) -> None:
from models.dataset import Document, DocumentPipelineExecutionLog, Pipeline
# 1. Setup mocks
@ -850,7 +879,7 @@ def test_retry_error_document_success(mocker, rag_pipeline_service) -> None:
# --- set_datasource_variables ---
def test_set_datasource_variables_success(mocker, rag_pipeline_service) -> None:
def test_set_datasource_variables_success(mocker: MockerFixture, rag_pipeline_service: RagPipelineService) -> None:
from graphon.entities.workflow_node_execution import WorkflowNodeExecution
from models.dataset import Pipeline
@ -909,7 +938,7 @@ def test_set_datasource_variables_success(mocker, rag_pipeline_service) -> None:
# --- Utility Methods ---
def test_get_draft_workflow_success(mocker, rag_pipeline_service) -> None:
def test_get_draft_workflow_success(mocker: MockerFixture, rag_pipeline_service: RagPipelineService) -> None:
# 1. Setup mocks
pipeline = _make_pipeline()
@ -925,7 +954,7 @@ def test_get_draft_workflow_success(mocker, rag_pipeline_service) -> None:
assert result == workflow
def test_get_published_workflow_success(mocker, rag_pipeline_service) -> None:
def test_get_published_workflow_success(mocker: MockerFixture, rag_pipeline_service: RagPipelineService) -> None:
# 1. Setup mocks
pipeline = _make_pipeline(workflow_id="wf-pub")
@ -941,7 +970,7 @@ def test_get_published_workflow_success(mocker, rag_pipeline_service) -> None:
assert result == workflow
def test_get_default_block_configs_success(rag_pipeline_service) -> None:
def test_get_default_block_configs_success(rag_pipeline_service: RagPipelineService) -> None:
# This calls static methods on node classes, should be safe with default mocks or as-is
# unless they access db.
result = rag_pipeline_service.get_default_block_configs()
@ -949,7 +978,7 @@ def test_get_default_block_configs_success(rag_pipeline_service) -> None:
assert len(result) > 0
def test_get_default_block_config_success(rag_pipeline_service) -> None:
def test_get_default_block_config_success(rag_pipeline_service: RagPipelineService) -> None:
from graphon.enums import BuiltinNodeTypes
result = rag_pipeline_service.get_default_block_config(BuiltinNodeTypes.LLM)
@ -957,7 +986,9 @@ def test_get_default_block_config_success(rag_pipeline_service) -> None:
assert result["type"] == "llm"
def test_publish_workflow_raises_when_draft_workflow_missing(mocker, rag_pipeline_service) -> None:
def test_publish_workflow_raises_when_draft_workflow_missing(
mocker: MockerFixture, rag_pipeline_service: RagPipelineService
) -> None:
session = mocker.Mock()
session.scalar.return_value = None
pipeline = _make_pipeline()
@ -967,7 +998,9 @@ def test_publish_workflow_raises_when_draft_workflow_missing(mocker, rag_pipelin
rag_pipeline_service.publish_workflow(session=session, pipeline=pipeline, account=account)
def test_get_default_block_config_returns_none_when_mapped_type_missing(mocker, rag_pipeline_service) -> None:
def test_get_default_block_config_returns_none_when_mapped_type_missing(
mocker: MockerFixture, rag_pipeline_service: RagPipelineService
) -> None:
from graphon.enums import BuiltinNodeTypes
mocker.patch("services.rag_pipeline.rag_pipeline.get_node_type_classes_mapping", return_value={})
@ -975,7 +1008,9 @@ def test_get_default_block_config_returns_none_when_mapped_type_missing(mocker,
assert rag_pipeline_service.get_default_block_config(BuiltinNodeTypes.START) is None
def test_get_default_block_config_injects_http_request_filter(mocker, rag_pipeline_service) -> None:
def test_get_default_block_config_injects_http_request_filter(
mocker: MockerFixture, rag_pipeline_service: RagPipelineService
) -> None:
from graphon.enums import BuiltinNodeTypes
fake_node_cls = mocker.Mock()
@ -992,7 +1027,9 @@ def test_get_default_block_config_injects_http_request_filter(mocker, rag_pipeli
assert "http_request_config" in called_filters
def test_run_draft_workflow_node_raises_when_workflow_missing(mocker, rag_pipeline_service) -> None:
def test_run_draft_workflow_node_raises_when_workflow_missing(
mocker: MockerFixture, rag_pipeline_service: RagPipelineService
) -> None:
pipeline = _make_pipeline()
account = _make_account()
mocker.patch.object(rag_pipeline_service, "get_draft_workflow", return_value=None)
@ -1001,7 +1038,9 @@ def test_run_draft_workflow_node_raises_when_workflow_missing(mocker, rag_pipeli
rag_pipeline_service.run_draft_workflow_node(pipeline, "node-1", {}, account)
def test_run_draft_workflow_node_saves_execution_and_variables(mocker, rag_pipeline_service) -> None:
def test_run_draft_workflow_node_saves_execution_and_variables(
mocker: MockerFixture, rag_pipeline_service: RagPipelineService
) -> None:
mocker.patch("services.rag_pipeline.rag_pipeline.db", mocker.Mock(engine=mocker.Mock()))
pipeline = _make_pipeline()
account = _make_account()
@ -1035,7 +1074,9 @@ def test_run_draft_workflow_node_saves_execution_and_variables(mocker, rag_pipel
saver.save.assert_called_once()
def test_run_datasource_workflow_node_returns_error_when_workflow_missing(mocker, rag_pipeline_service) -> None:
def test_run_datasource_workflow_node_returns_error_when_workflow_missing(
mocker: MockerFixture, rag_pipeline_service: RagPipelineService
) -> None:
pipeline = SimpleNamespace(id="p1", tenant_id="t1")
mocker.patch.object(rag_pipeline_service, "get_draft_workflow", return_value=None)
@ -1053,7 +1094,9 @@ def test_run_datasource_workflow_node_returns_error_when_workflow_missing(mocker
assert events[0]["event"] == "datasource_error"
def test_run_datasource_workflow_node_online_document_success(mocker, rag_pipeline_service) -> None:
def test_run_datasource_workflow_node_online_document_success(
mocker: MockerFixture, rag_pipeline_service: RagPipelineService
) -> None:
from core.datasource.entities.datasource_entities import DatasourceProviderType
pipeline = SimpleNamespace(id="p1", tenant_id="t1")
@ -1099,7 +1142,9 @@ def test_run_datasource_workflow_node_online_document_success(mocker, rag_pipeli
assert events[1]["event"] == "datasource_completed"
def test_run_datasource_workflow_node_online_drive_success(mocker, rag_pipeline_service) -> None:
def test_run_datasource_workflow_node_online_drive_success(
mocker: MockerFixture, rag_pipeline_service: RagPipelineService
) -> None:
from core.datasource.entities.datasource_entities import DatasourceProviderType
pipeline = SimpleNamespace(id="p1", tenant_id="t1")
@ -1145,7 +1190,9 @@ def test_run_datasource_workflow_node_online_drive_success(mocker, rag_pipeline_
assert events[1]["event"] == "datasource_completed"
def test_handle_node_run_result_default_value_strategy(mocker, rag_pipeline_service) -> None:
def test_handle_node_run_result_default_value_strategy(
mocker: MockerFixture, rag_pipeline_service: RagPipelineService
) -> None:
from datetime import datetime
from graphon.enums import BuiltinNodeTypes, ErrorStrategy, WorkflowNodeExecutionStatus
@ -1190,7 +1237,9 @@ def test_handle_node_run_result_default_value_strategy(mocker, rag_pipeline_serv
assert result.outputs["fallback"] == "ok"
def test_get_first_step_parameters_raises_when_datasource_node_missing(mocker, rag_pipeline_service) -> None:
def test_get_first_step_parameters_raises_when_datasource_node_missing(
mocker: MockerFixture, rag_pipeline_service: RagPipelineService
) -> None:
workflow = SimpleNamespace(graph_dict={"nodes": []}, rag_pipeline_variables=[{"variable": "url"}])
mocker.patch.object(rag_pipeline_service, "get_published_workflow", return_value=workflow)
@ -1198,7 +1247,9 @@ def test_get_first_step_parameters_raises_when_datasource_node_missing(mocker, r
rag_pipeline_service.get_first_step_parameters(SimpleNamespace(), "missing-node")
def test_get_second_step_parameters_handles_string_and_list_variable_references(mocker, rag_pipeline_service) -> None:
def test_get_second_step_parameters_handles_string_and_list_variable_references(
mocker: MockerFixture, rag_pipeline_service: RagPipelineService
) -> None:
workflow = SimpleNamespace(
rag_pipeline_variables=[
{"variable": "url", "belong_to_node_id": "node-1"},
@ -1226,7 +1277,9 @@ def test_get_second_step_parameters_handles_string_and_list_variable_references(
assert result == [{"variable": "keep", "belong_to_node_id": "node-1"}]
def test_get_rag_pipeline_workflow_run_node_executions_empty_when_run_missing(mocker, rag_pipeline_service) -> None:
def test_get_rag_pipeline_workflow_run_node_executions_empty_when_run_missing(
mocker: MockerFixture, rag_pipeline_service: RagPipelineService
) -> None:
pipeline = _make_pipeline()
mocker.patch.object(rag_pipeline_service, "get_rag_pipeline_workflow_run", return_value=None)
@ -1237,7 +1290,9 @@ def test_get_rag_pipeline_workflow_run_node_executions_empty_when_run_missing(mo
assert result == []
def test_get_rag_pipeline_workflow_run_node_executions_returns_sorted_executions(mocker, rag_pipeline_service) -> None:
def test_get_rag_pipeline_workflow_run_node_executions_returns_sorted_executions(
mocker: MockerFixture, rag_pipeline_service: RagPipelineService
) -> None:
mocker.patch("services.rag_pipeline.rag_pipeline.db", mocker.Mock(engine=mocker.Mock()))
pipeline = _make_pipeline()
mocker.patch.object(rag_pipeline_service, "get_rag_pipeline_workflow_run", return_value=SimpleNamespace(id="run-1"))
@ -1252,7 +1307,9 @@ def test_get_rag_pipeline_workflow_run_node_executions_returns_sorted_executions
assert result == ["n1", "n2"]
def test_get_recommended_plugins_returns_empty_when_no_active_plugins(mocker, rag_pipeline_service) -> None:
def test_get_recommended_plugins_returns_empty_when_no_active_plugins(
mocker: MockerFixture, rag_pipeline_service: RagPipelineService
) -> None:
mock_db = mocker.patch("services.rag_pipeline.rag_pipeline.db")
mock_db.session.scalars.return_value.all.return_value = []
@ -1264,7 +1321,9 @@ def test_get_recommended_plugins_returns_empty_when_no_active_plugins(mocker, ra
}
def test_get_recommended_plugins_returns_installed_and_uninstalled(mocker, rag_pipeline_service) -> None:
def test_get_recommended_plugins_returns_installed_and_uninstalled(
mocker: MockerFixture, rag_pipeline_service: RagPipelineService
) -> None:
plugin_a = _make_recommended_plugin("plugin-a")
plugin_b = _make_recommended_plugin("plugin-b")
mock_db = mocker.patch("services.rag_pipeline.rag_pipeline.db")
@ -1284,7 +1343,9 @@ def test_get_recommended_plugins_returns_installed_and_uninstalled(mocker, rag_p
assert result["uninstalled_recommended_plugins"] == [{"plugin_id": "plugin-b", "name": "Plugin B"}]
def test_get_node_last_run_delegates_to_repository(mocker, rag_pipeline_service) -> None:
def test_get_node_last_run_delegates_to_repository(
mocker: MockerFixture, rag_pipeline_service: RagPipelineService
) -> None:
mocker.patch("services.rag_pipeline.rag_pipeline.db", mocker.Mock(engine=mocker.Mock()))
repo = mocker.Mock()
repo.get_node_last_execution.return_value = "node-exec"
@ -1300,7 +1361,9 @@ def test_get_node_last_run_delegates_to_repository(mocker, rag_pipeline_service)
assert result == "node-exec"
def test_set_datasource_variables_raises_when_node_id_missing(mocker, rag_pipeline_service) -> None:
def test_set_datasource_variables_raises_when_node_id_missing(
mocker: MockerFixture, rag_pipeline_service: RagPipelineService
) -> None:
pipeline = SimpleNamespace(id="p1", tenant_id="t1")
workflow = mocker.Mock()
mocker.patch.object(rag_pipeline_service, "get_draft_workflow", return_value=workflow)
@ -1309,7 +1372,9 @@ def test_set_datasource_variables_raises_when_node_id_missing(mocker, rag_pipeli
rag_pipeline_service.set_datasource_variables(pipeline, {"start_node_id": ""}, SimpleNamespace(id="u1"))
def test_get_default_block_configs_skips_empty_configs(mocker, rag_pipeline_service) -> None:
def test_get_default_block_configs_skips_empty_configs(
mocker: MockerFixture, rag_pipeline_service: RagPipelineService
) -> None:
from graphon.enums import BuiltinNodeTypes
http_node = mocker.Mock()
@ -1333,7 +1398,9 @@ def test_get_default_block_configs_skips_empty_configs(mocker, rag_pipeline_serv
empty_node.get_default_config.assert_called_once()
def test_run_datasource_workflow_node_returns_error_when_node_missing(mocker, rag_pipeline_service) -> None:
def test_run_datasource_workflow_node_returns_error_when_node_missing(
mocker: MockerFixture, rag_pipeline_service: RagPipelineService
) -> None:
pipeline = SimpleNamespace(id="p1", tenant_id="t1")
workflow = SimpleNamespace(graph_dict={"nodes": []})
mocker.patch.object(rag_pipeline_service, "get_published_workflow", return_value=workflow)
@ -1353,7 +1420,9 @@ def test_run_datasource_workflow_node_returns_error_when_node_missing(mocker, ra
assert "Datasource node data not found" in events[0]["error"]
def test_run_datasource_workflow_node_online_document_exception(mocker, rag_pipeline_service) -> None:
def test_run_datasource_workflow_node_online_document_exception(
mocker: MockerFixture, rag_pipeline_service: RagPipelineService
) -> None:
pipeline = SimpleNamespace(id="p1", tenant_id="t1")
workflow = SimpleNamespace(
graph_dict={
@ -1405,7 +1474,9 @@ def test_run_datasource_workflow_node_online_document_exception(mocker, rag_pipe
assert "doc failed" in events[1]["error"]
def test_run_datasource_node_preview_raises_for_stream_non_string(mocker, rag_pipeline_service) -> None:
def test_run_datasource_node_preview_raises_for_stream_non_string(
mocker: MockerFixture, rag_pipeline_service: RagPipelineService
) -> None:
from core.datasource.entities.datasource_entities import DatasourceMessage
pipeline = SimpleNamespace(id="p1", tenant_id="t1")
@ -1453,7 +1524,9 @@ def test_run_datasource_node_preview_raises_for_stream_non_string(mocker, rag_pi
)
def test_get_first_step_parameters_returns_empty_when_no_rag_variables(mocker, rag_pipeline_service) -> None:
def test_get_first_step_parameters_returns_empty_when_no_rag_variables(
mocker: MockerFixture, rag_pipeline_service: RagPipelineService
) -> None:
workflow = SimpleNamespace(
graph_dict={"nodes": [{"id": "node-1", "data": {"datasource_parameters": {"url": {"value": "literal"}}}}]},
rag_pipeline_variables=[],
@ -1465,7 +1538,9 @@ def test_get_first_step_parameters_returns_empty_when_no_rag_variables(mocker, r
assert result == []
def test_get_second_step_parameters_filters_first_step_variables(mocker, rag_pipeline_service) -> None:
def test_get_second_step_parameters_filters_first_step_variables(
mocker: MockerFixture, rag_pipeline_service: RagPipelineService
) -> None:
workflow = SimpleNamespace(
graph_dict={
"nodes": [
@ -1494,7 +1569,9 @@ def test_get_second_step_parameters_filters_first_step_variables(mocker, rag_pip
assert result == [{"variable": "keep", "belong_to_node_id": "shared"}]
def test_retry_error_document_raises_when_execution_log_not_found(mocker, rag_pipeline_service) -> None:
def test_retry_error_document_raises_when_execution_log_not_found(
mocker: MockerFixture, rag_pipeline_service: RagPipelineService
) -> None:
mocker.patch("services.rag_pipeline.rag_pipeline.db.session.scalar", return_value=None)
with pytest.raises(ValueError, match="Document pipeline execution log not found"):
@ -1503,7 +1580,9 @@ def test_retry_error_document_raises_when_execution_log_not_found(mocker, rag_pi
)
def test_get_datasource_plugins_raises_when_workflow_not_found(mocker, rag_pipeline_service) -> None:
def test_get_datasource_plugins_raises_when_workflow_not_found(
mocker: MockerFixture, rag_pipeline_service: RagPipelineService
) -> None:
dataset = SimpleNamespace(pipeline_id="p1")
pipeline = SimpleNamespace(id="p1", tenant_id="t1")
mocker.patch("services.rag_pipeline.rag_pipeline.db.session.scalar", side_effect=[dataset, pipeline])
@ -1513,7 +1592,9 @@ def test_get_datasource_plugins_raises_when_workflow_not_found(mocker, rag_pipel
rag_pipeline_service.get_datasource_plugins("t1", "d1", True)
def test_handle_node_run_result_raises_when_no_terminal_event(mocker, rag_pipeline_service) -> None:
def test_handle_node_run_result_raises_when_no_terminal_event(
mocker: MockerFixture, rag_pipeline_service: RagPipelineService
) -> None:
node_instance = SimpleNamespace(
workflow_id="wf-1",
node_type="start",
@ -1534,7 +1615,9 @@ def test_handle_node_run_result_raises_when_no_terminal_event(mocker, rag_pipeli
)
def test_handle_node_run_result_marks_document_error_for_published_invoke(mocker, rag_pipeline_service) -> None:
def test_handle_node_run_result_marks_document_error_for_published_invoke(
mocker: MockerFixture, rag_pipeline_service: RagPipelineService
) -> None:
from core.app.entities.app_invoke_entities import InvokeFrom
from graphon.enums import WorkflowNodeExecutionStatus
from graphon.graph_events import NodeRunFailedEvent
@ -1595,7 +1678,9 @@ def test_handle_node_run_result_marks_document_error_for_published_invoke(mocker
commit_mock.assert_called_once()
def test_run_datasource_node_preview_raises_for_unsupported_provider(mocker, rag_pipeline_service) -> None:
def test_run_datasource_node_preview_raises_for_unsupported_provider(
mocker: MockerFixture, rag_pipeline_service: RagPipelineService
) -> None:
pipeline = SimpleNamespace(id="p1", tenant_id="t1")
workflow = SimpleNamespace(
graph_dict={
@ -1631,14 +1716,18 @@ def test_run_datasource_node_preview_raises_for_unsupported_provider(mocker, rag
)
def test_publish_customized_pipeline_template_raises_for_missing_pipeline(mocker, rag_pipeline_service) -> None:
def test_publish_customized_pipeline_template_raises_for_missing_pipeline(
mocker: MockerFixture, rag_pipeline_service: RagPipelineService
) -> None:
mocker.patch("services.rag_pipeline.rag_pipeline.db.session.get", return_value=None)
with pytest.raises(ValueError, match="Pipeline not found"):
rag_pipeline_service.publish_customized_pipeline_template("p1", {}, _make_account(), "t1")
def test_publish_customized_pipeline_template_raises_for_missing_workflow_id(mocker, rag_pipeline_service) -> None:
def test_publish_customized_pipeline_template_raises_for_missing_workflow_id(
mocker: MockerFixture, rag_pipeline_service: RagPipelineService
) -> None:
pipeline = _make_pipeline(workflow_id=None)
mocker.patch("services.rag_pipeline.rag_pipeline.db.session.get", return_value=pipeline)
@ -1648,14 +1737,18 @@ def test_publish_customized_pipeline_template_raises_for_missing_workflow_id(moc
)
def test_get_pipeline_raises_when_dataset_missing(mocker, rag_pipeline_service) -> None:
def test_get_pipeline_raises_when_dataset_missing(
mocker: MockerFixture, rag_pipeline_service: RagPipelineService
) -> None:
mocker.patch("services.rag_pipeline.rag_pipeline.db.session.scalar", return_value=None)
with pytest.raises(ValueError, match="Dataset not found"):
rag_pipeline_service.get_pipeline("t1", "d1")
def test_get_pipeline_raises_when_pipeline_missing(mocker, rag_pipeline_service) -> None:
def test_get_pipeline_raises_when_pipeline_missing(
mocker: MockerFixture, rag_pipeline_service: RagPipelineService
) -> None:
dataset = SimpleNamespace(pipeline_id="p1")
mocker.patch("services.rag_pipeline.rag_pipeline.db.session.scalar", side_effect=[dataset, None])
@ -1663,7 +1756,7 @@ def test_get_pipeline_raises_when_pipeline_missing(mocker, rag_pipeline_service)
rag_pipeline_service.get_pipeline("t1", "d1")
def test_init_uses_default_sessionmaker_when_none(mocker) -> None:
def test_init_uses_default_sessionmaker_when_none(mocker: MockerFixture) -> None:
default_session_maker = mocker.Mock()
mocker.patch("services.rag_pipeline.rag_pipeline.sessionmaker", return_value=default_session_maker)
mocker.patch("services.rag_pipeline.rag_pipeline.db", SimpleNamespace(engine=mocker.Mock()))
@ -1680,7 +1773,7 @@ def test_init_uses_default_sessionmaker_when_none(mocker) -> None:
create_run_repo.assert_called_once_with(default_session_maker)
def test_get_pipeline_templates_builtin_en_us_no_fallback(mocker) -> None:
def test_get_pipeline_templates_builtin_en_us_no_fallback(mocker: MockerFixture) -> None:
mocker.patch("services.rag_pipeline.rag_pipeline.dify_config.HOSTED_FETCH_PIPELINE_TEMPLATES_MODE", "remote")
retrieval = mocker.Mock()
retrieval.get_pipeline_templates.return_value = {"pipeline_templates": []}
@ -1694,7 +1787,7 @@ def test_get_pipeline_templates_builtin_en_us_no_fallback(mocker) -> None:
builtin.fetch_pipeline_templates_from_builtin.assert_not_called()
def test_update_customized_pipeline_template_commits_when_name_empty(mocker) -> None:
def test_update_customized_pipeline_template_commits_when_name_empty(mocker: MockerFixture) -> None:
template = _make_customized_template()
mocker.patch("services.rag_pipeline.rag_pipeline.db.session.scalar", return_value=template)
commit = mocker.patch("services.rag_pipeline.rag_pipeline.db.session.commit")
@ -1706,7 +1799,7 @@ def test_update_customized_pipeline_template_commits_when_name_empty(mocker) ->
commit.assert_called_once()
def test_get_all_published_workflow_without_filters_has_no_more(rag_pipeline_service) -> None:
def test_get_all_published_workflow_without_filters_has_no_more(rag_pipeline_service: RagPipelineService) -> None:
session = SimpleNamespace(scalars=lambda stmt: SimpleNamespace(all=lambda: ["wf1"]))
pipeline = _make_pipeline(workflow_id="wf-live")
@ -1723,7 +1816,9 @@ def test_get_all_published_workflow_without_filters_has_no_more(rag_pipeline_ser
assert has_more is False
def test_publish_workflow_skips_dataset_update_for_non_knowledge_nodes(mocker, rag_pipeline_service) -> None:
def test_publish_workflow_skips_dataset_update_for_non_knowledge_nodes(
mocker: MockerFixture, rag_pipeline_service: RagPipelineService
) -> None:
draft = SimpleNamespace(
type="workflow",
graph={"nodes": [{"data": {"type": "start"}}]},
@ -1747,7 +1842,9 @@ def test_publish_workflow_skips_dataset_update_for_non_knowledge_nodes(mocker, r
assert result is published
def test_get_default_block_config_returns_none_when_default_empty(mocker, rag_pipeline_service) -> None:
def test_get_default_block_config_returns_none_when_default_empty(
mocker: MockerFixture, rag_pipeline_service: RagPipelineService
) -> None:
from graphon.enums import BuiltinNodeTypes
node_cls = mocker.Mock()
@ -1761,7 +1858,9 @@ def test_get_default_block_config_returns_none_when_default_empty(mocker, rag_pi
assert rag_pipeline_service.get_default_block_config("start") is None
def test_run_datasource_workflow_node_handles_variable_parameter_types(mocker, rag_pipeline_service) -> None:
def test_run_datasource_workflow_node_handles_variable_parameter_types(
mocker: MockerFixture, rag_pipeline_service: RagPipelineService
) -> None:
from core.datasource.entities.datasource_entities import DatasourceProviderType
workflow = SimpleNamespace(
@ -1811,7 +1910,9 @@ def test_run_datasource_workflow_node_handles_variable_parameter_types(mocker, r
assert events[0]["data"] == []
def test_run_datasource_workflow_node_online_drive_branch(mocker, rag_pipeline_service) -> None:
def test_run_datasource_workflow_node_online_drive_branch(
mocker: MockerFixture, rag_pipeline_service: RagPipelineService
) -> None:
from core.datasource.entities.datasource_entities import DatasourceProviderType
workflow = SimpleNamespace(
@ -1857,7 +1958,9 @@ def test_run_datasource_workflow_node_online_drive_branch(mocker, rag_pipeline_s
assert events[1]["data"] == {"items": [1]}
def test_run_datasource_node_preview_not_published_uses_draft(mocker, rag_pipeline_service) -> None:
def test_run_datasource_node_preview_not_published_uses_draft(
mocker: MockerFixture, rag_pipeline_service: RagPipelineService
) -> None:
from core.datasource.entities.datasource_entities import DatasourceMessage
workflow = SimpleNamespace(
@ -1903,7 +2006,9 @@ def test_run_datasource_node_preview_not_published_uses_draft(mocker, rag_pipeli
get_draft.assert_called_once()
def test_run_free_workflow_node_delegates_to_handle_result(mocker, rag_pipeline_service) -> None:
def test_run_free_workflow_node_delegates_to_handle_result(
mocker: MockerFixture, rag_pipeline_service: RagPipelineService
) -> None:
expected = SimpleNamespace(id="exec-1")
handle = mocker.patch.object(rag_pipeline_service, "_handle_node_run_result", return_value=expected)
@ -1919,7 +2024,9 @@ def test_run_free_workflow_node_delegates_to_handle_result(mocker, rag_pipeline_
handle.assert_called_once()
def test_publish_customized_pipeline_template_raises_when_workflow_missing(mocker, rag_pipeline_service) -> None:
def test_publish_customized_pipeline_template_raises_when_workflow_missing(
mocker: MockerFixture, rag_pipeline_service: RagPipelineService
) -> None:
pipeline = _make_pipeline(workflow_id="wf-1")
mocker.patch("services.rag_pipeline.rag_pipeline.db.session.get", side_effect=[pipeline, None])
@ -1927,7 +2034,9 @@ def test_publish_customized_pipeline_template_raises_when_workflow_missing(mocke
rag_pipeline_service.publish_customized_pipeline_template("p1", {}, _make_account(), "t1")
def test_publish_customized_pipeline_template_raises_when_dataset_missing(mocker, rag_pipeline_service) -> None:
def test_publish_customized_pipeline_template_raises_when_dataset_missing(
mocker: MockerFixture, rag_pipeline_service: RagPipelineService
) -> None:
pipeline = _make_pipeline(workflow_id="wf-1")
workflow = _make_workflow(workflow_id="wf-1")
mock_db = mocker.patch("services.rag_pipeline.rag_pipeline.db")
@ -1940,7 +2049,9 @@ def test_publish_customized_pipeline_template_raises_when_dataset_missing(mocker
rag_pipeline_service.publish_customized_pipeline_template("p1", {}, _make_account(), "t1")
def test_get_recommended_plugins_skips_manifest_when_missing(mocker, rag_pipeline_service) -> None:
def test_get_recommended_plugins_skips_manifest_when_missing(
mocker: MockerFixture, rag_pipeline_service: RagPipelineService
) -> None:
plugin = _make_recommended_plugin("plugin-a")
mock_db = mocker.patch("services.rag_pipeline.rag_pipeline.db")
mock_db.session.scalars.return_value.all.return_value = [plugin]
@ -1953,7 +2064,9 @@ def test_get_recommended_plugins_skips_manifest_when_missing(mocker, rag_pipelin
assert result["uninstalled_recommended_plugins"] == []
def test_retry_error_document_raises_when_pipeline_missing(mocker, rag_pipeline_service) -> None:
def test_retry_error_document_raises_when_pipeline_missing(
mocker: MockerFixture, rag_pipeline_service: RagPipelineService
) -> None:
exec_log = SimpleNamespace(pipeline_id="p1")
mocker.patch("services.rag_pipeline.rag_pipeline.db.session.scalar", return_value=exec_log)
mocker.patch("services.rag_pipeline.rag_pipeline.db.session.get", return_value=None)
@ -1964,7 +2077,9 @@ def test_retry_error_document_raises_when_pipeline_missing(mocker, rag_pipeline_
)
def test_retry_error_document_raises_when_workflow_missing(mocker, rag_pipeline_service) -> None:
def test_retry_error_document_raises_when_workflow_missing(
mocker: MockerFixture, rag_pipeline_service: RagPipelineService
) -> None:
exec_log = SimpleNamespace(pipeline_id="p1")
pipeline = SimpleNamespace(id="p1")
mocker.patch("services.rag_pipeline.rag_pipeline.db.session.scalar", return_value=exec_log)
@ -1977,7 +2092,9 @@ def test_retry_error_document_raises_when_workflow_missing(mocker, rag_pipeline_
)
def test_get_datasource_plugins_returns_empty_for_non_datasource_nodes(mocker, rag_pipeline_service) -> None:
def test_get_datasource_plugins_returns_empty_for_non_datasource_nodes(
mocker: MockerFixture, rag_pipeline_service: RagPipelineService
) -> None:
dataset = _make_dataset()
pipeline = _make_pipeline()
workflow = SimpleNamespace(
@ -1989,7 +2106,9 @@ def test_get_datasource_plugins_returns_empty_for_non_datasource_nodes(mocker, r
assert rag_pipeline_service.get_datasource_plugins("t1", "d1", True) == []
def test_publish_workflow_raises_when_knowledge_index_dataset_missing(mocker, rag_pipeline_service) -> None:
def test_publish_workflow_raises_when_knowledge_index_dataset_missing(
mocker: MockerFixture, rag_pipeline_service: RagPipelineService
) -> None:
draft = SimpleNamespace(
type="workflow",
graph={"nodes": [{"data": {"type": "knowledge-index"}}]},
@ -2012,7 +2131,9 @@ def test_publish_workflow_raises_when_knowledge_index_dataset_missing(mocker, ra
rag_pipeline_service.publish_workflow(session=session, pipeline=pipeline, account=SimpleNamespace(id="u1"))
def test_run_datasource_node_preview_raises_when_workflow_missing(mocker, rag_pipeline_service) -> None:
def test_run_datasource_node_preview_raises_when_workflow_missing(
mocker: MockerFixture, rag_pipeline_service: RagPipelineService
) -> None:
mocker.patch.object(rag_pipeline_service, "get_published_workflow", return_value=None)
with pytest.raises(RuntimeError, match="Workflow not initialized"):
@ -2026,7 +2147,9 @@ def test_run_datasource_node_preview_raises_when_workflow_missing(mocker, rag_pi
)
def test_run_datasource_node_preview_raises_when_node_missing(mocker, rag_pipeline_service) -> None:
def test_run_datasource_node_preview_raises_when_node_missing(
mocker: MockerFixture, rag_pipeline_service: RagPipelineService
) -> None:
mocker.patch.object(
rag_pipeline_service, "get_published_workflow", return_value=SimpleNamespace(graph_dict={"nodes": []})
)
@ -2042,7 +2165,9 @@ def test_run_datasource_node_preview_raises_when_node_missing(mocker, rag_pipeli
)
def test_run_datasource_node_preview_keeps_existing_user_input(mocker, rag_pipeline_service) -> None:
def test_run_datasource_node_preview_keeps_existing_user_input(
mocker: MockerFixture, rag_pipeline_service: RagPipelineService
) -> None:
from core.datasource.entities.datasource_entities import DatasourceMessage
workflow = SimpleNamespace(
@ -2088,7 +2213,9 @@ def test_run_datasource_node_preview_keeps_existing_user_input(mocker, rag_pipel
assert result == {"ok": "1"}
def test_run_datasource_node_preview_ignores_non_variable_messages(mocker, rag_pipeline_service) -> None:
def test_run_datasource_node_preview_ignores_non_variable_messages(
mocker: MockerFixture, rag_pipeline_service: RagPipelineService
) -> None:
workflow = SimpleNamespace(
graph_dict={
"nodes": [
@ -2127,7 +2254,9 @@ def test_run_datasource_node_preview_ignores_non_variable_messages(mocker, rag_p
assert result == {}
def test_set_datasource_variables_raises_when_workflow_missing(mocker, rag_pipeline_service) -> None:
def test_set_datasource_variables_raises_when_workflow_missing(
mocker: MockerFixture, rag_pipeline_service: RagPipelineService
) -> None:
mocker.patch.object(rag_pipeline_service, "get_draft_workflow", return_value=None)
with pytest.raises(ValueError, match="Workflow not initialized"):
@ -2138,7 +2267,9 @@ def test_set_datasource_variables_raises_when_workflow_missing(mocker, rag_pipel
)
def test_get_datasource_plugins_handles_empty_datasource_data_and_non_published(mocker, rag_pipeline_service) -> None:
def test_get_datasource_plugins_handles_empty_datasource_data_and_non_published(
mocker: MockerFixture, rag_pipeline_service: RagPipelineService
) -> None:
dataset = _make_dataset()
pipeline = _make_pipeline()
workflow = SimpleNamespace(
@ -2156,7 +2287,9 @@ def test_get_datasource_plugins_handles_empty_datasource_data_and_non_published(
assert len(result) == 1
def test_get_datasource_plugins_extracts_user_inputs_and_credentials(mocker, rag_pipeline_service) -> None:
def test_get_datasource_plugins_extracts_user_inputs_and_credentials(
mocker: MockerFixture, rag_pipeline_service: RagPipelineService
) -> None:
dataset = _make_dataset()
pipeline = _make_pipeline()
workflow = SimpleNamespace(
@ -2198,7 +2331,9 @@ def test_get_datasource_plugins_extracts_user_inputs_and_credentials(mocker, rag
assert result[0]["credentials"][0]["id"] == "c1"
def test_get_pipeline_returns_pipeline_when_found(mocker, rag_pipeline_service) -> None:
def test_get_pipeline_returns_pipeline_when_found(
mocker: MockerFixture, rag_pipeline_service: RagPipelineService
) -> None:
dataset = _make_dataset()
pipeline = _make_pipeline()
mocker.patch("services.rag_pipeline.rag_pipeline.db.session.scalar", side_effect=[dataset, pipeline])

View File

@ -23,7 +23,7 @@ def proxy(mocker: MockerFixture):
# --- delay ---
def test_delay_with_empty_entities_logs_warning_and_returns(mocker) -> None:
def test_delay_with_empty_entities_logs_warning_and_returns(mocker: MockerFixture) -> None:
mocker.patch("services.rag_pipeline.rag_pipeline_task_proxy.TenantIsolatedTaskQueue")
proxy = RagPipelineTaskProxy(
dataset_tenant_id="tenant-1",
@ -37,7 +37,7 @@ def test_delay_with_empty_entities_logs_warning_and_returns(mocker) -> None:
dispatch_mock.assert_not_called()
def test_delay_with_entities_calls_dispatch(mocker, proxy) -> None:
def test_delay_with_entities_calls_dispatch(mocker: MockerFixture, proxy) -> None:
dispatch_mock = mocker.patch.object(proxy, "_dispatch")
proxy.delay()
@ -48,7 +48,7 @@ def test_delay_with_entities_calls_dispatch(mocker, proxy) -> None:
# --- _dispatch ---
def test_dispatch_billing_sandbox_uses_default_tenant_queue(mocker, proxy) -> None:
def test_dispatch_billing_sandbox_uses_default_tenant_queue(mocker: MockerFixture, proxy) -> None:
upload_mock = mocker.patch.object(proxy, "_upload_invoke_entities", return_value="file-1")
send_mock = mocker.patch.object(proxy, "_send_to_default_tenant_queue")
@ -65,7 +65,7 @@ def test_dispatch_billing_sandbox_uses_default_tenant_queue(mocker, proxy) -> No
send_mock.assert_called_once_with("file-1")
def test_dispatch_billing_non_sandbox_uses_priority_tenant_queue(mocker, proxy) -> None:
def test_dispatch_billing_non_sandbox_uses_priority_tenant_queue(mocker: MockerFixture, proxy) -> None:
upload_mock = mocker.patch.object(proxy, "_upload_invoke_entities", return_value="file-1")
send_mock = mocker.patch.object(proxy, "_send_to_priority_tenant_queue")
@ -82,7 +82,7 @@ def test_dispatch_billing_non_sandbox_uses_priority_tenant_queue(mocker, proxy)
send_mock.assert_called_once_with("file-1")
def test_dispatch_no_billing_uses_priority_direct_queue(mocker, proxy) -> None:
def test_dispatch_no_billing_uses_priority_direct_queue(mocker: MockerFixture, proxy) -> None:
upload_mock = mocker.patch.object(proxy, "_upload_invoke_entities", return_value="file-1")
send_mock = mocker.patch.object(proxy, "_send_to_priority_direct_queue")
@ -95,7 +95,7 @@ def test_dispatch_no_billing_uses_priority_direct_queue(mocker, proxy) -> None:
send_mock.assert_called_once_with("file-1")
def test_dispatch_raises_on_empty_upload_file_id(mocker, proxy) -> None:
def test_dispatch_raises_on_empty_upload_file_id(mocker: MockerFixture, proxy) -> None:
mocker.patch.object(proxy, "_upload_invoke_entities", return_value="")
features = SimpleNamespace(billing=SimpleNamespace(enabled=False, subscription=SimpleNamespace(plan="free")))
@ -108,7 +108,7 @@ def test_dispatch_raises_on_empty_upload_file_id(mocker, proxy) -> None:
# --- _send_to_direct_queue ---
def test_send_to_direct_queue_calls_task_func_delay(mocker, proxy) -> None:
def test_send_to_direct_queue_calls_task_func_delay(mocker: MockerFixture, proxy) -> None:
task_func = Mock()
proxy._send_to_direct_queue("file-1", task_func)
@ -122,7 +122,7 @@ def test_send_to_direct_queue_calls_task_func_delay(mocker, proxy) -> None:
# --- _send_to_tenant_queue ---
def test_send_to_tenant_queue_pushes_when_task_key_exists(mocker, proxy) -> None:
def test_send_to_tenant_queue_pushes_when_task_key_exists(mocker: MockerFixture, proxy) -> None:
proxy._tenant_isolated_task_queue.get_task_key.return_value = "existing-key"
task_func = Mock()
@ -132,7 +132,7 @@ def test_send_to_tenant_queue_pushes_when_task_key_exists(mocker, proxy) -> None
task_func.delay.assert_not_called()
def test_send_to_tenant_queue_sets_waiting_time_and_calls_delay(mocker, proxy) -> None:
def test_send_to_tenant_queue_sets_waiting_time_and_calls_delay(mocker: MockerFixture, proxy) -> None:
proxy._tenant_isolated_task_queue.get_task_key.return_value = None
task_func = Mock()
@ -148,7 +148,7 @@ def test_send_to_tenant_queue_sets_waiting_time_and_calls_delay(mocker, proxy) -
# --- _upload_invoke_entities ---
def test_upload_invoke_entities_returns_file_id(mocker, proxy) -> None:
def test_upload_invoke_entities_returns_file_id(mocker: MockerFixture, proxy) -> None:
upload_file = SimpleNamespace(id="uploaded-file-1")
file_service_cls = mocker.patch("services.rag_pipeline.rag_pipeline_task_proxy.FileService")
file_service_cls.return_value.upload_text.return_value = upload_file

View File

@ -81,7 +81,7 @@ def sample_form_record():
)
def test_enqueue_resume_dispatches_task_for_workflow(mocker, mock_session_factory):
def test_enqueue_resume_dispatches_task_for_workflow(mocker: MockerFixture, mock_session_factory):
session_factory, session = mock_session_factory
service = HumanInputService(session_factory)
@ -108,7 +108,9 @@ def test_enqueue_resume_dispatches_task_for_workflow(mocker, mock_session_factor
assert call_kwargs["kwargs"]["payload"]["workflow_run_id"] == "workflow-run-id"
def test_ensure_form_active_respects_global_timeout(monkeypatch, sample_form_record, mock_session_factory):
def test_ensure_form_active_respects_global_timeout(
monkeypatch, sample_form_record: HumanInputFormRecord, mock_session_factory
):
session_factory, _ = mock_session_factory
service = HumanInputService(session_factory)
expired_record = dataclasses.replace(
@ -122,7 +124,7 @@ def test_ensure_form_active_respects_global_timeout(monkeypatch, sample_form_rec
service.ensure_form_active(Form(expired_record))
def test_enqueue_resume_dispatches_task_for_advanced_chat(mocker, mock_session_factory):
def test_enqueue_resume_dispatches_task_for_advanced_chat(mocker: MockerFixture, mock_session_factory):
session_factory, session = mock_session_factory
service = HumanInputService(session_factory)
@ -149,7 +151,7 @@ def test_enqueue_resume_dispatches_task_for_advanced_chat(mocker, mock_session_f
assert call_kwargs["kwargs"]["payload"]["workflow_run_id"] == "workflow-run-id"
def test_enqueue_resume_skips_unsupported_app_mode(mocker, mock_session_factory):
def test_enqueue_resume_skips_unsupported_app_mode(mocker: MockerFixture, mock_session_factory):
session_factory, session = mock_session_factory
service = HumanInputService(session_factory)
@ -174,7 +176,9 @@ def test_enqueue_resume_skips_unsupported_app_mode(mocker, mock_session_factory)
resume_task.apply_async.assert_not_called()
def test_get_form_definition_by_token_for_console_uses_repository(sample_form_record, mock_session_factory):
def test_get_form_definition_by_token_for_console_uses_repository(
sample_form_record: HumanInputFormRecord, mock_session_factory
):
session_factory, _ = mock_session_factory
repo = MagicMock(spec=HumanInputFormSubmissionRepository)
console_record = dataclasses.replace(sample_form_record, recipient_type=RecipientType.CONSOLE)
@ -215,7 +219,9 @@ def _build_resumption_context_state(*, options: list[str], workflow_run_id: str)
return context.dumps().encode()
def test_resolve_form_inputs_uses_runtime_select_options(sample_form_record, mock_session_factory, mocker):
def test_resolve_form_inputs_uses_runtime_select_options(
sample_form_record: HumanInputFormRecord, mock_session_factory, mocker: MockerFixture
):
session_factory, _ = mock_session_factory
configured_input = SelectInputConfig(
output_variable_name="decision",
@ -360,7 +366,7 @@ def test_submit_form_by_token_passes_submission_user_id(
enqueue_spy.assert_called_once_with(sample_form_record.workflow_run_id)
def test_submit_form_by_token_invalid_action(sample_form_record, mock_session_factory):
def test_submit_form_by_token_invalid_action(sample_form_record: HumanInputFormRecord, mock_session_factory):
session_factory, _ = mock_session_factory
repo = MagicMock(spec=HumanInputFormSubmissionRepository)
repo.get_by_token.return_value = dataclasses.replace(sample_form_record)
@ -378,7 +384,7 @@ def test_submit_form_by_token_invalid_action(sample_form_record, mock_session_fa
repo.mark_submitted.assert_not_called()
def test_submit_form_by_token_missing_inputs(sample_form_record, mock_session_factory):
def test_submit_form_by_token_missing_inputs(sample_form_record: HumanInputFormRecord, mock_session_factory):
session_factory, _ = mock_session_factory
repo = MagicMock(spec=HumanInputFormSubmissionRepository)
@ -559,7 +565,7 @@ def test_get_form_by_token_none(mock_session_factory):
assert service.get_form_by_token("invalid") is None
def test_get_form_definition_by_token_mismatch(sample_form_record, mock_session_factory):
def test_get_form_definition_by_token_mismatch(sample_form_record: HumanInputFormRecord, mock_session_factory):
session_factory, _ = mock_session_factory
repo = MagicMock(spec=HumanInputFormSubmissionRepository)
repo.get_by_token.return_value = sample_form_record
@ -569,7 +575,7 @@ def test_get_form_definition_by_token_mismatch(sample_form_record, mock_session_
assert service.get_form_definition_by_token(RecipientType.CONSOLE, "token") is None
def test_get_form_definition_by_token_success(sample_form_record, mock_session_factory):
def test_get_form_definition_by_token_success(sample_form_record: HumanInputFormRecord, mock_session_factory):
session_factory, _ = mock_session_factory
repo = MagicMock(spec=HumanInputFormSubmissionRepository)
repo.get_by_token.return_value = sample_form_record
@ -580,7 +586,9 @@ def test_get_form_definition_by_token_success(sample_form_record, mock_session_f
assert form.id == sample_form_record.form_id
def test_get_form_definition_by_token_for_console_mismatch(sample_form_record, mock_session_factory):
def test_get_form_definition_by_token_for_console_mismatch(
sample_form_record: HumanInputFormRecord, mock_session_factory
):
session_factory, _ = mock_session_factory
repo = MagicMock(spec=HumanInputFormSubmissionRepository)
repo.get_by_token.return_value = sample_form_record # is STANDALONE_WEB_APP
@ -599,7 +607,9 @@ def test_submit_form_by_token_delivery_not_enabled(mock_session_factory):
service.submit_form_by_token(RecipientType.STANDALONE_WEB_APP, "token", "action", {})
def test_submit_form_by_token_no_workflow_run_id(sample_form_record, mock_session_factory, mocker: MockerFixture):
def test_submit_form_by_token_no_workflow_run_id(
sample_form_record: HumanInputFormRecord, mock_session_factory, mocker: MockerFixture
):
session_factory, _ = mock_session_factory
repo = MagicMock(spec=HumanInputFormSubmissionRepository)
repo.get_by_token.return_value = sample_form_record
@ -615,7 +625,7 @@ def test_submit_form_by_token_no_workflow_run_id(sample_form_record, mock_sessio
enqueue_spy.assert_not_called()
def test_ensure_form_active_errors(sample_form_record, mock_session_factory):
def test_ensure_form_active_errors(sample_form_record: HumanInputFormRecord, mock_session_factory):
session_factory, _ = mock_session_factory
service = HumanInputService(session_factory)
@ -637,7 +647,7 @@ def test_ensure_form_active_errors(sample_form_record, mock_session_factory):
service.ensure_form_active(Form(expired_time_record))
def test_ensure_not_submitted_raises(sample_form_record, mock_session_factory):
def test_ensure_not_submitted_raises(sample_form_record: HumanInputFormRecord, mock_session_factory):
session_factory, _ = mock_session_factory
service = HumanInputService(session_factory)
submitted_record = dataclasses.replace(sample_form_record, submitted_at=naive_utc_now())
@ -646,7 +656,7 @@ def test_ensure_not_submitted_raises(sample_form_record, mock_session_factory):
service._ensure_not_submitted(Form(submitted_record))
def test_enqueue_resume_workflow_not_found(mocker, mock_session_factory):
def test_enqueue_resume_workflow_not_found(mocker: MockerFixture, mock_session_factory):
session_factory, _ = mock_session_factory
service = HumanInputService(session_factory)
@ -662,7 +672,7 @@ def test_enqueue_resume_workflow_not_found(mocker, mock_session_factory):
assert "WorkflowRun not found" in str(excinfo.value)
def test_enqueue_resume_app_not_found(mocker, mock_session_factory):
def test_enqueue_resume_app_not_found(mocker: MockerFixture, mock_session_factory):
session_factory, session = mock_session_factory
service = HumanInputService(session_factory)
@ -683,7 +693,9 @@ def test_enqueue_resume_app_not_found(mocker, mock_session_factory):
logger_spy.error.assert_called_once()
def test_is_globally_expired_zero_timeout(monkeypatch, sample_form_record, mock_session_factory):
def test_is_globally_expired_zero_timeout(
monkeypatch: pytest.MonkeyPatch, sample_form_record: HumanInputFormRecord, mock_session_factory
):
session_factory, _ = mock_session_factory
service = HumanInputService(session_factory)
@ -691,7 +703,9 @@ def test_is_globally_expired_zero_timeout(monkeypatch, sample_form_record, mock_
assert service._is_globally_expired(Form(sample_form_record)) is False
def test_submit_form_by_token_normalizes_select_and_files(sample_form_record, mock_session_factory, mocker) -> None:
def test_submit_form_by_token_normalizes_select_and_files(
sample_form_record: HumanInputFormRecord, mock_session_factory, mocker: MockerFixture
) -> None:
session_factory, _ = mock_session_factory
repo = MagicMock(spec=HumanInputFormSubmissionRepository)
definition = FormDefinition(
@ -772,7 +786,9 @@ def test_submit_form_by_token_normalizes_select_and_files(sample_form_record, mo
enqueue_spy.assert_called_once_with(sample_form_record.workflow_run_id)
def test_submit_form_by_token_invalid_select_value(sample_form_record, mock_session_factory) -> None:
def test_submit_form_by_token_invalid_select_value(
sample_form_record: HumanInputFormRecord, mock_session_factory
) -> None:
session_factory, _ = mock_session_factory
repo = MagicMock(spec=HumanInputFormSubmissionRepository)
definition = FormDefinition(
@ -799,7 +815,9 @@ def test_submit_form_by_token_invalid_select_value(sample_form_record, mock_sess
)
def test_submit_form_by_token_invalid_file_list_item(sample_form_record, mock_session_factory) -> None:
def test_submit_form_by_token_invalid_file_list_item(
sample_form_record: HumanInputFormRecord, mock_session_factory
) -> None:
session_factory, _ = mock_session_factory
repo = MagicMock(spec=HumanInputFormSubmissionRepository)
definition = FormDefinition(
@ -824,7 +842,9 @@ def test_submit_form_by_token_invalid_file_list_item(sample_form_record, mock_se
)
def test_submit_form_by_token_rejects_cross_tenant_file(sample_form_record, mock_session_factory, mocker) -> None:
def test_submit_form_by_token_rejects_cross_tenant_file(
sample_form_record: HumanInputFormRecord, mock_session_factory, mocker: MockerFixture
) -> None:
session_factory, _ = mock_session_factory
repo = MagicMock(spec=HumanInputFormSubmissionRepository)
definition = FormDefinition(
@ -855,7 +875,9 @@ def test_submit_form_by_token_rejects_cross_tenant_file(sample_form_record, mock
repo.mark_submitted.assert_not_called()
def test_submit_form_by_token_rejects_cross_tenant_file_list(sample_form_record, mock_session_factory, mocker) -> None:
def test_submit_form_by_token_rejects_cross_tenant_file_list(
sample_form_record: HumanInputFormRecord, mock_session_factory, mocker: MockerFixture
) -> None:
session_factory, _ = mock_session_factory
repo = MagicMock(spec=HumanInputFormSubmissionRepository)
definition = FormDefinition(