mirror of
https://github.com/langgenius/dify.git
synced 2026-05-05 01:48:04 +08:00
refactor: replace sa.String with EnumText in mapped_column for type s… (#33332)
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@ -165,7 +165,7 @@ class TestChatMessageApiPermissions:
|
||||
agent_thoughts=[],
|
||||
message_files=[],
|
||||
message_metadata_dict={},
|
||||
status="success",
|
||||
status="normal",
|
||||
error="",
|
||||
parent_message_id=None,
|
||||
)
|
||||
|
||||
@ -3331,7 +3331,7 @@ class TestRegisterService:
|
||||
TenantService.create_tenant_member(tenant, account, role="normal")
|
||||
|
||||
# Change tenant status to non-normal
|
||||
tenant.status = "suspended"
|
||||
tenant.status = "archive"
|
||||
|
||||
db_session_with_containers.commit()
|
||||
|
||||
|
||||
@ -2,6 +2,7 @@ import uuid
|
||||
from unittest.mock import ANY, MagicMock, patch
|
||||
|
||||
import pytest
|
||||
import sqlalchemy as sa
|
||||
from faker import Faker
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
@ -492,20 +493,20 @@ class TestAppGenerateService:
|
||||
)
|
||||
|
||||
# Manually set invalid mode after creation
|
||||
# With EnumText, invalid values are rejected at the DB level during flush,
|
||||
# raising StatementError wrapping ValueError
|
||||
app.mode = "invalid_mode"
|
||||
|
||||
# Setup test arguments
|
||||
args = {"inputs": {"query": fake.text(max_nb_chars=50)}, "response_mode": "streaming"}
|
||||
|
||||
# Execute the method under test and expect ValueError
|
||||
with pytest.raises(ValueError) as exc_info:
|
||||
# Execute the method under test and expect either ValueError (direct) or
|
||||
# StatementError (from EnumText validation during autoflush)
|
||||
with pytest.raises((ValueError, sa.exc.StatementError)):
|
||||
AppGenerateService.generate(
|
||||
app_model=app, user=account, args=args, invoke_from=InvokeFrom.SERVICE_API, streaming=True
|
||||
)
|
||||
|
||||
# Verify error message
|
||||
assert "Invalid app mode" in str(exc_info.value)
|
||||
|
||||
def test_generate_with_workflow_id_format_error(
|
||||
self, db_session_with_containers: Session, mock_external_service_dependencies
|
||||
):
|
||||
|
||||
@ -163,7 +163,7 @@ class TestSavedMessageService:
|
||||
answer_unit_price=0.002,
|
||||
total_price=0.003,
|
||||
currency="USD",
|
||||
status="success",
|
||||
status="normal",
|
||||
)
|
||||
|
||||
db_session_with_containers.add(message)
|
||||
|
||||
@ -62,7 +62,7 @@ class TestWorkflowService:
|
||||
tenant = Tenant(
|
||||
name=f"Test Tenant {fake.company()}",
|
||||
plan="basic",
|
||||
status="active",
|
||||
status="normal",
|
||||
)
|
||||
tenant.id = account.current_tenant_id
|
||||
tenant.created_at = fake.date_time_this_year()
|
||||
@ -1090,20 +1090,19 @@ class TestWorkflowService:
|
||||
|
||||
This test ensures that the service correctly handles feature validation
|
||||
for unsupported app modes, preventing invalid operations.
|
||||
With EnumText, invalid values are rejected at the DB level during flush,
|
||||
raising StatementError wrapping ValueError.
|
||||
"""
|
||||
# Arrange
|
||||
fake = Faker()
|
||||
app = self._create_test_app(db_session_with_containers, fake)
|
||||
app.mode = "invalid_mode" # Invalid mode
|
||||
|
||||
db_session_with_containers.commit()
|
||||
# Act & Assert - EnumText validation rejects invalid values at DB flush
|
||||
import sqlalchemy as sa
|
||||
|
||||
workflow_service = WorkflowService()
|
||||
features = {"test": "value"}
|
||||
|
||||
# Act & Assert
|
||||
with pytest.raises(ValueError, match="Invalid app mode: invalid_mode"):
|
||||
workflow_service.validate_features_structure(app_model=app, features=features)
|
||||
with pytest.raises((ValueError, sa.exc.StatementError)):
|
||||
db_session_with_containers.commit()
|
||||
|
||||
def test_update_workflow_success(self, db_session_with_containers: Session):
|
||||
"""
|
||||
|
||||
@ -110,7 +110,7 @@ class TestCleanDatasetTask:
|
||||
tenant = Tenant(
|
||||
name=fake.company(),
|
||||
plan="basic",
|
||||
status="active",
|
||||
status="normal",
|
||||
)
|
||||
|
||||
db_session_with_containers.add(tenant)
|
||||
|
||||
@ -48,7 +48,7 @@ class TestDeleteSegmentFromIndexTask:
|
||||
Tenant: Created test tenant instance
|
||||
"""
|
||||
fake = fake or Faker()
|
||||
tenant = Tenant(name=f"Test Tenant {fake.company()}", plan="basic", status="active")
|
||||
tenant = Tenant(name=f"Test Tenant {fake.company()}", plan="basic", status="normal")
|
||||
tenant.id = fake.uuid4()
|
||||
tenant.created_at = fake.date_time_this_year()
|
||||
tenant.updated_at = tenant.created_at
|
||||
|
||||
@ -65,7 +65,7 @@ class TestDisableSegmentsFromIndexTask:
|
||||
tenant = Tenant(
|
||||
name=f"Test Tenant {fake.company()}",
|
||||
plan="basic",
|
||||
status="active",
|
||||
status="normal",
|
||||
)
|
||||
tenant.id = account.tenant_id
|
||||
tenant.created_at = fake.date_time_this_year()
|
||||
|
||||
@ -118,7 +118,7 @@ class TestSendEmailCodeLoginMailTask:
|
||||
tenant = Tenant(
|
||||
name=fake.company(),
|
||||
plan="basic",
|
||||
status="active",
|
||||
status="normal",
|
||||
)
|
||||
|
||||
db_session_with_containers.add(tenant)
|
||||
|
||||
@ -48,7 +48,7 @@ def make_message():
|
||||
msg.query = "hello"
|
||||
msg.re_sign_file_url_answer = ""
|
||||
msg.user_feedback = MagicMock(rating=None)
|
||||
msg.status = "success"
|
||||
msg.status = "normal"
|
||||
msg.error = None
|
||||
return msg
|
||||
|
||||
|
||||
@ -137,7 +137,7 @@ def test_message_list_mapping(app: Flask) -> None:
|
||||
{"id": "file-dict", "filename": "a.txt", "type": "file", "transfer_method": "local"},
|
||||
message_file_obj,
|
||||
],
|
||||
status="success",
|
||||
status="normal",
|
||||
error=None,
|
||||
message_metadata_dict={"meta": "value"},
|
||||
extra_contents=[
|
||||
|
||||
@ -3730,7 +3730,7 @@ class TestDatasetRetrievalAdditionalHelpers:
|
||||
attachment_ids=None,
|
||||
dataset_ids=["d1"],
|
||||
app_id="a1",
|
||||
user_from="web",
|
||||
user_from="account",
|
||||
user_id="u1",
|
||||
)
|
||||
mock_session.add_all.assert_not_called()
|
||||
@ -3740,7 +3740,7 @@ class TestDatasetRetrievalAdditionalHelpers:
|
||||
attachment_ids=["f1"],
|
||||
dataset_ids=["d1", "d2"],
|
||||
app_id="a1",
|
||||
user_from="web",
|
||||
user_from="account",
|
||||
user_id="u1",
|
||||
)
|
||||
mock_session.add_all.assert_called()
|
||||
|
||||
@ -5,6 +5,7 @@ from typing import Any
|
||||
from unittest.mock import patch
|
||||
|
||||
from core.app.entities.app_invoke_entities import InvokeFrom
|
||||
from core.helper.tool_parameter_cache import ToolParameterCache
|
||||
from core.tools.__base.tool import Tool
|
||||
from core.tools.__base.tool_runtime import ToolRuntime
|
||||
from core.tools.entities.common_entities import I18nObject
|
||||
@ -112,37 +113,38 @@ def test_encrypt_tool_parameters():
|
||||
def test_decrypt_tool_parameters_cache_hit_and_miss():
|
||||
manager = _build_manager()
|
||||
|
||||
with patch("core.tools.utils.configuration.ToolParameterCache") as cache_cls:
|
||||
cache = cache_cls.return_value
|
||||
cache.get.return_value = {"secret": "cached"}
|
||||
with (
|
||||
patch.object(ToolParameterCache, "get", return_value={"secret": "cached"}),
|
||||
patch.object(ToolParameterCache, "set") as mock_set,
|
||||
):
|
||||
assert manager.decrypt_tool_parameters({"secret": "enc"}) == {"secret": "cached"}
|
||||
cache.set.assert_not_called()
|
||||
mock_set.assert_not_called()
|
||||
|
||||
with patch("core.tools.utils.configuration.ToolParameterCache") as cache_cls:
|
||||
cache = cache_cls.return_value
|
||||
cache.get.return_value = None
|
||||
with patch("core.tools.utils.configuration.encrypter.decrypt_token", return_value="dec"):
|
||||
decrypted = manager.decrypt_tool_parameters({"secret": "enc", "plain": "x"})
|
||||
|
||||
assert decrypted["secret"] == "dec"
|
||||
cache.set.assert_called_once()
|
||||
with (
|
||||
patch.object(ToolParameterCache, "get", return_value=None),
|
||||
patch.object(ToolParameterCache, "set") as mock_set,
|
||||
patch("core.tools.utils.configuration.encrypter.decrypt_token", return_value="dec"),
|
||||
):
|
||||
decrypted = manager.decrypt_tool_parameters({"secret": "enc", "plain": "x"})
|
||||
assert decrypted["secret"] == "dec"
|
||||
mock_set.assert_called_once()
|
||||
|
||||
|
||||
def test_delete_tool_parameters_cache():
|
||||
manager = _build_manager()
|
||||
|
||||
with patch("core.tools.utils.configuration.ToolParameterCache") as cache_cls:
|
||||
with patch.object(ToolParameterCache, "delete") as mock_delete:
|
||||
manager.delete_tool_parameters_cache()
|
||||
|
||||
cache_cls.return_value.delete.assert_called_once()
|
||||
mock_delete.assert_called_once()
|
||||
|
||||
|
||||
def test_configuration_manager_decrypt_suppresses_errors():
|
||||
manager = _build_manager()
|
||||
with patch("core.tools.utils.configuration.ToolParameterCache") as cache_cls:
|
||||
cache = cache_cls.return_value
|
||||
cache.get.return_value = None
|
||||
with patch("core.tools.utils.configuration.encrypter.decrypt_token", side_effect=RuntimeError("boom")):
|
||||
decrypted = manager.decrypt_tool_parameters({"secret": "enc"})
|
||||
with (
|
||||
patch.object(ToolParameterCache, "get", return_value=None),
|
||||
patch("core.tools.utils.configuration.encrypter.decrypt_token", side_effect=RuntimeError("boom")),
|
||||
):
|
||||
decrypted = manager.decrypt_tool_parameters({"secret": "enc"})
|
||||
# decryption failure is suppressed, original value is retained.
|
||||
assert decrypted["secret"] == "enc"
|
||||
|
||||
@ -98,7 +98,7 @@ class TestAccountModelValidation:
|
||||
)
|
||||
|
||||
# Assert
|
||||
assert account.status == "active"
|
||||
assert account.status == AccountStatus.ACTIVE
|
||||
|
||||
def test_account_get_status_method(self):
|
||||
"""Test the get_status method returns AccountStatus enum."""
|
||||
@ -106,7 +106,7 @@ class TestAccountModelValidation:
|
||||
account = Account(
|
||||
name="Test User",
|
||||
email="test@example.com",
|
||||
status="pending",
|
||||
status=AccountStatus.PENDING,
|
||||
)
|
||||
|
||||
# Act
|
||||
|
||||
Reference in New Issue
Block a user