test: update unit tests for system message handling and workflow collaboration serices

This commit is contained in:
Novice
2026-03-19 17:19:56 +08:00
parent fefbd84c67
commit 2ce7919e6d
9 changed files with 45 additions and 17 deletions

View File

@ -134,8 +134,8 @@ class TestInitSystemMessage:
assert result == []
def test_existing_system_message_not_duplicated(self, mock_runner):
"""Test that system message is not duplicated if already present."""
def test_existing_system_message_replaced_with_template(self, mock_runner):
"""Test that existing system message is replaced with the new template."""
existing_messages = [
SystemPromptMessage(content="Existing system"),
UserPromptMessage(content="User message"),
@ -143,9 +143,8 @@ class TestInitSystemMessage:
result = mock_runner._init_system_message("New template", existing_messages)
# Should not insert new system message
assert len(result) == 2
assert result[0].content == "Existing system"
assert result[0].content == "New template"
def test_system_message_inserted_when_missing(self, mock_runner):
"""Test that system message is inserted when first message is not system."""

View File

@ -105,9 +105,12 @@ def test_generate_appends_pause_layer_and_forwards_state(mocker):
graph_runtime_state = MagicMock()
workflow_mock = MagicMock()
workflow_mock.get_feature.return_value.enabled = False
result = generator._generate(
app_model=app_model,
workflow=MagicMock(),
workflow=workflow_mock,
user=MagicMock(),
application_generate_entity=application_generate_entity,
invoke_from="service-api",
@ -143,8 +146,15 @@ def test_resume_path_runs_worker_with_runtime_state(mocker):
fake_db = SimpleNamespace(session=MagicMock(), engine=MagicMock())
mocker.patch("core.app.apps.workflow.app_generator.db", fake_db)
sandbox_feature = SimpleNamespace(enabled=False)
workflow = SimpleNamespace(
id="workflow", tenant_id="tenant", app_id="app", graph_dict={}, type="workflow", version="1"
id="workflow",
tenant_id="tenant",
app_id="app",
graph_dict={},
type="workflow",
version="1",
get_feature=lambda _feature: sandbox_feature,
)
end_user = SimpleNamespace(session_id="end-user-session")
app_record = SimpleNamespace(id="app")

View File

@ -38,6 +38,7 @@ class TestSegmentTypeIsArrayType:
SegmentType.NONE,
SegmentType.GROUP,
SegmentType.BOOLEAN,
SegmentType.ARRAY_PROMPT_MESSAGE,
]
for seg_type in expected_array_types:

View File

@ -581,11 +581,11 @@ class TestSegmentTypeIsValid:
test_value = None
elif segment_type == SegmentType.GROUP:
test_value = SegmentGroup(value=[StringSegment(value="test")])
elif segment_type == SegmentType.ARRAY_PROMPT_MESSAGE:
continue # Internal type, not validated via is_valid
elif segment_type.is_array_type():
test_value = [] # Empty array is valid for all array types
else:
# If we get here, there's a segment type we don't know how to test
# This should prompt us to add validation logic
pytest.fail(f"Unknown segment type {segment_type} needs validation logic and test case")
# This should NOT raise AssertionError
@ -788,6 +788,7 @@ class TestSegmentTypeValidationIntegration:
unhandled_types = {
SegmentType.INTEGER, # Handled by NUMBER validation logic
SegmentType.FLOAT, # Handled by NUMBER validation logic
SegmentType.ARRAY_PROMPT_MESSAGE, # Internal type, not user-facing
}
# Verify all types are accounted for

View File

@ -180,7 +180,8 @@ class TestBuildContext:
],
)
context = build_context(messages, "The weather in Beijing is sunny, 25°C.", generation_data)
accumulated_response = "Let me check the weather.The weather in Beijing is sunny, 25°C."
context = build_context(messages, accumulated_response, generation_data)
# Should have: user message + assistant with tool_call + tool result + final assistant
assert len(context) == 4
@ -263,7 +264,8 @@ class TestBuildContext:
],
)
context = build_context(messages, "Beijing is sunny at 25°C, Shanghai is cloudy at 22°C.", generation_data)
accumulated_response = "I'll check both cities.Beijing is sunny at 25°C, Shanghai is cloudy at 22°C."
context = build_context(messages, accumulated_response, generation_data)
# Should have: user + assistant with 2 tool_calls + 2 tool results + final assistant
assert len(context) == 5

View File

@ -45,6 +45,8 @@ class TestWorkflowCollaborationRepository:
"avatar": None,
"sid": "sid-1",
"connected_at": 2,
"graph_active": False,
"active_skill_file_id": None,
}
]

View File

@ -10,6 +10,13 @@ class TestWorkflowCollaborationService:
@pytest.fixture
def service(self) -> tuple[WorkflowCollaborationService, Mock, Mock]:
repository = Mock(spec=WorkflowCollaborationRepository)
repository.get_current_leader.return_value = None
repository.get_session_sids.return_value = []
repository.get_active_skill_file_id.return_value = None
repository.get_active_skill_session_sids.return_value = []
repository.is_graph_active.return_value = False
repository.get_skill_leader.return_value = None
repository.list_sessions.return_value = []
socketio = Mock()
return WorkflowCollaborationService(repository, socketio), repository, socketio
@ -124,6 +131,7 @@ class TestWorkflowCollaborationService:
# Arrange
collaboration_service, repository, _socketio = service
repository.get_current_leader.return_value = "sid-1"
repository.is_graph_active.return_value = True
with patch.object(collaboration_service, "is_session_active", return_value=True):
# Act
@ -265,6 +273,7 @@ class TestWorkflowCollaborationService:
# Arrange
collaboration_service, repository, _socketio = service
repository.get_current_leader.return_value = "sid-1"
repository.is_graph_active.return_value = True
with patch.object(collaboration_service, "is_session_active", return_value=True):
# Act

View File

@ -17,6 +17,10 @@ def mock_session(monkeypatch: pytest.MonkeyPatch) -> Mock:
mock_db.engine = Mock()
monkeypatch.setattr(service_module, "Session", Mock(return_value=context_manager))
monkeypatch.setattr(service_module, "db", mock_db)
monkeypatch.setattr(service_module, "send_workflow_comment_mention_email_task", Mock())
scalars_default = Mock()
scalars_default.all.return_value = []
session.scalars.return_value = scalars_default
return session

View File

@ -29,7 +29,7 @@ class TestSystemOAuthEncrypter:
def test_init_with_none_secret_key(self):
"""Test initialization with None secret key falls back to config"""
with patch("core.tools.utils.system_oauth_encryption.dify_config") as mock_config:
with patch("core.tools.utils.system_encryption.dify_config") as mock_config:
mock_config.SECRET_KEY = "config_secret"
encrypter = SystemEncrypter(secret_key=None)
expected_key = hashlib.sha256(b"config_secret").digest()
@ -43,7 +43,7 @@ class TestSystemOAuthEncrypter:
def test_init_without_secret_key_uses_config(self):
"""Test initialization without secret key uses config"""
with patch("core.tools.utils.system_oauth_encryption.dify_config") as mock_config:
with patch("core.tools.utils.system_encryption.dify_config") as mock_config:
mock_config.SECRET_KEY = "default_secret"
encrypter = SystemEncrypter()
expected_key = hashlib.sha256(b"default_secret").digest()
@ -302,7 +302,7 @@ class TestSystemOAuthEncrypter:
decrypted2 = encrypter2.decrypt_params(encrypted2)
assert decrypted1 == decrypted2 == oauth_params
@patch("core.tools.utils.system_oauth_encryption.get_random_bytes")
@patch("core.tools.utils.system_encryption.get_random_bytes")
def test_encrypt_oauth_params_crypto_error(self, mock_get_random_bytes):
"""Test encryption when crypto operation fails"""
mock_get_random_bytes.side_effect = Exception("Crypto error")
@ -315,7 +315,7 @@ class TestSystemOAuthEncrypter:
assert "Encryption failed" in str(exc_info.value)
@patch("core.tools.utils.system_oauth_encryption.TypeAdapter")
@patch("core.tools.utils.system_encryption.TypeAdapter")
def test_encrypt_oauth_params_serialization_error(self, mock_type_adapter):
"""Test encryption when JSON serialization fails"""
mock_type_adapter.return_value.dump_json.side_effect = Exception("Serialization error")
@ -370,7 +370,7 @@ class TestFactoryFunctions:
def test_create_system_oauth_encrypter_without_secret(self):
"""Test factory function without secret key"""
with patch("core.tools.utils.system_oauth_encryption.dify_config") as mock_config:
with patch("core.tools.utils.system_encryption.dify_config") as mock_config:
mock_config.SECRET_KEY = "config_secret"
encrypter = create_system_encrypter()
@ -380,7 +380,7 @@ class TestFactoryFunctions:
def test_create_system_oauth_encrypter_with_none_secret(self):
"""Test factory function with None secret key"""
with patch("core.tools.utils.system_oauth_encryption.dify_config") as mock_config:
with patch("core.tools.utils.system_encryption.dify_config") as mock_config:
mock_config.SECRET_KEY = "config_secret"
encrypter = create_system_encrypter(None)
@ -412,7 +412,7 @@ class TestGlobalEncrypterInstance:
core.tools.utils.system_encryption._encrypter = None
with patch("core.tools.utils.system_oauth_encryption.dify_config") as mock_config:
with patch("core.tools.utils.system_encryption.dify_config") as mock_config:
mock_config.SECRET_KEY = "global_secret"
encrypter = get_system_encrypter()