fix: fix test failed

This commit is contained in:
fatelei 2026-07-29 11:35:10 +08:00
parent 58f17aa5a8
commit f7dc60bf90
No known key found for this signature in database
GPG Key ID: 2F91DA05646F4EED
5 changed files with 143 additions and 83 deletions

View File

@ -48,9 +48,6 @@ from models.agent import (
AgentConfigRevisionOperation,
AgentConfigSnapshot,
AgentKind,
AgentRuntimeSession,
AgentRuntimeSessionOwnerType,
AgentRuntimeSessionStatus,
AgentScope,
AgentSource,
AgentStatus,
@ -1062,7 +1059,6 @@ class SkillManagementService:
model_config: AgentSoulModelConfig,
) -> None:
model_changed = False
cleaned_runtime_session_count = 0
if assistant.active_config_snapshot_id:
snapshot = session.get(AgentConfigSnapshot, assistant.active_config_snapshot_id)
if snapshot is not None:
@ -1094,24 +1090,11 @@ class SkillManagementService:
draft_config.model = model_config
draft.config_snapshot = draft_config
if model_changed:
for runtime_session in session.scalars(
select(AgentRuntimeSession).where(
AgentRuntimeSession.owner_type == AgentRuntimeSessionOwnerType.CONVERSATION,
AgentRuntimeSession.tenant_id == assistant.tenant_id,
AgentRuntimeSession.app_id == assistant.backing_app_id,
AgentRuntimeSession.agent_id == assistant.id,
AgentRuntimeSession.status == AgentRuntimeSessionStatus.ACTIVE,
)
):
runtime_session.status = AgentRuntimeSessionStatus.CLEANED
runtime_session.cleaned_at = naive_utc_now()
cleaned_runtime_session_count += 1
logger.info(
"skill_assistant_model_synced assistant_id=%s provider=%s model=%s cleaned_runtime_sessions=%s",
"skill_assistant_model_synced assistant_id=%s provider=%s model=%s",
assistant.id,
model_config.model_provider,
model_config.model,
cleaned_runtime_session_count,
)
def update_metadata(

View File

@ -33,7 +33,7 @@ def current_user() -> Account:
return user
def _skill_detail() -> dict:
def _skill_detail() -> dict[str, object]:
return {
"id": "skill-1",
"name": "finance-sop",
@ -92,13 +92,14 @@ def test_list_skills_uses_default_pagination_when_query_omits_page_and_limit(app
api = WorkspaceSkillsApi()
method = unwrap(api.get)
service = MagicMock()
service.list_skills.return_value = {
list_response: dict[str, object] = {
"data": [],
"has_more": False,
"limit": 20,
"page": 1,
"total": 0,
}
service.list_skills.return_value = list_response
with (
app.test_request_context("/?keyword=finance&tag=ops&tag=", method="GET"),
@ -236,7 +237,7 @@ def test_get_skill_version_returns_version_detail(app: Flask) -> None:
api = WorkspaceSkillVersionApi()
method = unwrap(api.get)
service = MagicMock()
service.get_version.return_value = {
version_response: dict[str, object] = {
"id": "version-1",
"skill_id": "skill-1",
"version_number": 1,
@ -262,6 +263,7 @@ def test_get_skill_version_returns_version_detail(app: Flask) -> None:
}
],
}
service.get_version.return_value = version_response
with (
app.test_request_context("/", method="GET"),
@ -341,11 +343,8 @@ def test_skill_assistant_runs_agent_app_stream(app: Flask, current_user: Account
api = WorkspaceSkillAssistMessageApi()
method = unwrap(api.post)
service = MagicMock()
assistant_app = MagicMock()
assistant_app.id = "assistant-app-1"
service.get_or_create_assistant_app.return_value = (assistant_app, "<skill_draft>draft</skill_draft>")
app_model = MagicMock()
app_response = MagicMock()
action_stream = MagicMock()
service.create_assistant_action_stream.return_value = action_stream
compact_response = MagicMock()
with (
@ -368,19 +367,18 @@ def test_skill_assistant_runs_agent_app_stream(app: Flask, current_user: Account
),
patch("controllers.console.workspace.skills.SkillManagementService", return_value=service),
patch(
"controllers.console.workspace.skills.db.session",
return_value=MagicMock(get=MagicMock(return_value=app_model)),
),
patch("controllers.console.workspace.skills.AppGenerateService.generate", return_value=app_response),
patch("controllers.console.workspace.skills.helper.compact_generate_response", return_value=compact_response),
"controllers.console.workspace.skills.helper.compact_generate_response",
return_value=compact_response,
) as compact_generate_response,
):
response = method(api, "tenant-1", current_user, "skill-1")
assert response is compact_response
service.get_or_create_assistant_app.assert_called_once_with(
service.create_assistant_action_stream.assert_called_once_with(
tenant_id="tenant-1",
skill_id="skill-1",
user_id="user-1",
message="Create an approval checklist.",
attachments=[
SkillAssistAttachmentPayload(
tool_file_id="tool-file-1",
@ -389,6 +387,7 @@ def test_skill_assistant_runs_agent_app_stream(app: Flask, current_user: Account
size=128,
)
],
message="Create an approval checklist.",
model_payload=None,
target_path=None,
)
compact_generate_response.assert_called_once_with(action_stream)

View File

@ -34,7 +34,7 @@ from models.agent_config_entities import AgentSoulConfig
def _no_runtime_agent_skills(monkeypatch: pytest.MonkeyPatch):
monkeypatch.setattr(
"core.app.apps.agent_app.runtime_request_builder.load_runtime_agent_skill_configs",
lambda *, tenant_id, agent_id: [],
lambda **_kwargs: [],
)
@ -523,7 +523,7 @@ class TestAgentAppConfigLayer:
def test_config_layer_includes_bound_workspace_skills(self, monkeypatch: pytest.MonkeyPatch):
monkeypatch.setattr(
"core.app.apps.agent_app.runtime_request_builder.load_runtime_agent_skill_configs",
lambda *, tenant_id, agent_id: [
lambda **_kwargs: [
DifyConfigSkillConfig(
name="workspace-skill",
description="Bound workspace skill.",

View File

@ -45,7 +45,7 @@ from models.agent_config_entities import (
def _no_runtime_agent_skills(monkeypatch: pytest.MonkeyPatch):
monkeypatch.setattr(
"core.workflow.nodes.agent_v2.runtime_request_builder.load_runtime_agent_skill_configs",
lambda *, tenant_id, agent_id: [],
lambda **_kwargs: [],
)
@ -1541,7 +1541,7 @@ def test_workflow_run_request_contains_config_layer():
def test_workflow_run_request_includes_bound_workspace_skills(monkeypatch: pytest.MonkeyPatch):
monkeypatch.setattr(
"core.workflow.nodes.agent_v2.runtime_request_builder.load_runtime_agent_skill_configs",
lambda *, tenant_id, agent_id: [
lambda **_kwargs: [
DifyConfigSkillConfig(
name="workspace-skill",
description="Bound workspace skill.",

View File

@ -7,13 +7,15 @@ import json
import zipfile
from collections.abc import Generator
from types import SimpleNamespace
from typing import cast, override
from unittest.mock import patch
from uuid import uuid4
import pytest
from sqlalchemy import delete, func, select
from sqlalchemy import Table, delete, func, select
from core.db.session_factory import session_factory
from core.tools.tool_file_manager import ToolFileManager
from models.account import Account
from models.agent import (
Agent,
@ -22,9 +24,6 @@ from models.agent import (
AgentConfigRevision,
AgentConfigSnapshot,
AgentKind,
AgentRuntimeSession,
AgentRuntimeSessionOwnerType,
AgentRuntimeSessionStatus,
AgentScope,
AgentSource,
AgentStatus,
@ -62,27 +61,33 @@ AGENT = "22222222-2222-2222-2222-222222222222"
USER = "33333333-3333-3333-3333-333333333333"
class _FakeToolFileManager:
def create_file_by_raw(self, **kwargs):
class _FakeToolFileManager(ToolFileManager):
@override
def create_file_by_raw(
self,
*,
user_id: str,
tenant_id: str,
conversation_id: str | None,
file_binary: bytes,
mimetype: str,
filename: str | None = None,
) -> ToolFile:
tool_file = ToolFile(
user_id=kwargs["user_id"],
tenant_id=kwargs["tenant_id"],
conversation_id=kwargs["conversation_id"],
user_id=user_id,
tenant_id=tenant_id,
conversation_id=conversation_id,
file_key=f"tools/{uuid4().hex}",
mimetype=kwargs["mimetype"],
mimetype=mimetype,
original_url=None,
name=kwargs.get("filename") or "file.bin",
size=len(kwargs["file_binary"]),
name=filename or "file.bin",
size=len(file_binary),
)
tool_file.id = str(uuid4())
with session_factory.create_session() as session:
session.add(tool_file)
session.commit()
return SimpleNamespace(
id=tool_file.id,
size=len(kwargs["file_binary"]),
mimetype=kwargs["mimetype"],
)
return tool_file
@pytest.fixture(autouse=True)
@ -95,7 +100,6 @@ def _tables() -> Generator[None, None, None]:
AgentConfigSnapshot,
AgentConfigDraft,
AgentConfigRevision,
AgentRuntimeSession,
ToolFile,
Tag,
TagBinding,
@ -106,7 +110,8 @@ def _tables() -> Generator[None, None, None]:
WorkflowAgentNodeBinding,
)
for model in models:
model.__table__.create(bind=engine, checkfirst=True)
table = cast(Table, model.__table__)
table.create(bind=engine, checkfirst=True)
_seed_agent()
yield
with session_factory.create_session() as session:
@ -455,17 +460,6 @@ def test_sync_assistant_model_config_updates_debugger_draft() -> None:
updated_by=USER,
)
session.add(draft)
runtime_session = AgentRuntimeSession(
tenant_id=TENANT,
app_id=agent.backing_app_id,
owner_type=AgentRuntimeSessionOwnerType.CONVERSATION,
agent_id=agent.id,
agent_config_snapshot_id=draft.id,
conversation_id=str(uuid4()),
session_snapshot="{}",
status=AgentRuntimeSessionStatus.ACTIVE,
)
session.add(runtime_session)
session.flush()
SkillManagementService._sync_assistant_model_config(
@ -479,7 +473,6 @@ def test_sync_assistant_model_config_updates_debugger_draft() -> None:
assert updated_draft.model is not None
assert updated_draft.model.model_provider == "langgenius/tongyi/tongyi"
assert updated_draft.model.model == "qwen3.7-plus"
assert runtime_session.status == AgentRuntimeSessionStatus.CLEANED
def test_sync_assistant_model_config_updates_draft_without_active_snapshot() -> None:
@ -1148,9 +1141,26 @@ def test_publish_archive_contains_synced_skill_md() -> None:
captured: dict[str, bytes] = {}
class CapturingToolFileManager(_FakeToolFileManager):
def create_file_by_raw(self, **kwargs):
captured["archive"] = kwargs["file_binary"]
return super().create_file_by_raw(**kwargs)
@override
def create_file_by_raw(
self,
*,
user_id: str,
tenant_id: str,
conversation_id: str | None,
file_binary: bytes,
mimetype: str,
filename: str | None = None,
) -> ToolFile:
captured["archive"] = file_binary
return super().create_file_by_raw(
user_id=user_id,
tenant_id=tenant_id,
conversation_id=conversation_id,
file_binary=file_binary,
mimetype=mimetype,
filename=filename,
)
service = SkillManagementService(tool_file_manager=CapturingToolFileManager())
created = service.create_skill(
@ -1173,9 +1183,26 @@ def test_list_versions_includes_publisher_name_and_version_detail_files() -> Non
captured: dict[str, bytes] = {}
class CapturingToolFileManager(_FakeToolFileManager):
def create_file_by_raw(self, **kwargs):
captured["archive"] = kwargs["file_binary"]
return super().create_file_by_raw(**kwargs)
@override
def create_file_by_raw(
self,
*,
user_id: str,
tenant_id: str,
conversation_id: str | None,
file_binary: bytes,
mimetype: str,
filename: str | None = None,
) -> ToolFile:
captured["archive"] = file_binary
return super().create_file_by_raw(
user_id=user_id,
tenant_id=tenant_id,
conversation_id=conversation_id,
file_binary=file_binary,
mimetype=mimetype,
filename=filename,
)
service = SkillManagementService(tool_file_manager=CapturingToolFileManager())
created = service.create_skill(
@ -1607,9 +1634,26 @@ def test_duplicate_skill_copies_latest_published_content_without_history() -> No
captured: dict[str, bytes] = {}
class CapturingToolFileManager(_FakeToolFileManager):
def create_file_by_raw(self, **kwargs):
captured["archive"] = kwargs["file_binary"]
return super().create_file_by_raw(**kwargs)
@override
def create_file_by_raw(
self,
*,
user_id: str,
tenant_id: str,
conversation_id: str | None,
file_binary: bytes,
mimetype: str,
filename: str | None = None,
) -> ToolFile:
captured["archive"] = file_binary
return super().create_file_by_raw(
user_id=user_id,
tenant_id=tenant_id,
conversation_id=conversation_id,
file_binary=file_binary,
mimetype=mimetype,
filename=filename,
)
service = SkillManagementService(tool_file_manager=CapturingToolFileManager())
created = service.create_skill(
@ -1834,9 +1878,26 @@ def test_publish_and_export_include_binary_tool_files() -> None:
captured: dict[str, bytes] = {}
class CapturingToolFileManager(_FakeToolFileManager):
def create_file_by_raw(self, **kwargs):
captured["archive"] = kwargs["file_binary"]
return super().create_file_by_raw(**kwargs)
@override
def create_file_by_raw(
self,
*,
user_id: str,
tenant_id: str,
conversation_id: str | None,
file_binary: bytes,
mimetype: str,
filename: str | None = None,
) -> ToolFile:
captured["archive"] = file_binary
return super().create_file_by_raw(
user_id=user_id,
tenant_id=tenant_id,
conversation_id=conversation_id,
file_binary=file_binary,
mimetype=mimetype,
filename=filename,
)
service = SkillManagementService(tool_file_manager=CapturingToolFileManager())
created = service.create_skill(tenant_id=TENANT, user_id=USER, payload=SkillCreatePayload(name="finance-sop"))
@ -1883,9 +1944,26 @@ def test_restore_version_replaces_draft_and_creates_new_published_version() -> N
captured: list[bytes] = []
class CapturingToolFileManager(_FakeToolFileManager):
def create_file_by_raw(self, **kwargs):
captured.append(kwargs["file_binary"])
return super().create_file_by_raw(**kwargs)
@override
def create_file_by_raw(
self,
*,
user_id: str,
tenant_id: str,
conversation_id: str | None,
file_binary: bytes,
mimetype: str,
filename: str | None = None,
) -> ToolFile:
captured.append(file_binary)
return super().create_file_by_raw(
user_id=user_id,
tenant_id=tenant_id,
conversation_id=conversation_id,
file_binary=file_binary,
mimetype=mimetype,
filename=filename,
)
service = SkillManagementService(tool_file_manager=CapturingToolFileManager())
created = service.create_skill(tenant_id=TENANT, user_id=USER, payload=SkillCreatePayload(name="finance-sop"))