This commit is contained in:
QuantumGhost
2025-11-06 11:23:28 +08:00
parent 7e06225ce2
commit 8b914d9116
53 changed files with 235712 additions and 33 deletions

View File

@ -161,3 +161,292 @@ class TestWorkflowService:
assert workflows == []
assert has_more is False
mock_session.scalars.assert_called_once()
class TestWorkflowServiceHumanInputValidation:
@pytest.fixture
def workflow_service(self):
# Mock sessionmaker to avoid database dependency
mock_session_maker = MagicMock()
return WorkflowService(mock_session_maker)
def test_validate_graph_structure_valid_human_input(self, workflow_service):
"""Test validation of valid HumanInput node data."""
graph = {
"nodes": [
{
"id": "node-1",
"data": {
"type": "human_input",
"title": "Human Input",
"delivery_methods": [{"type": "webapp", "enabled": True, "config": {}}],
"form_content": "Please provide your input",
"inputs": [
{
"type": "text-input",
"output_variable_name": "user_input",
"placeholder": {"type": "constant", "value": "Enter text here"},
}
],
"user_actions": [{"id": "submit", "title": "Submit", "button_style": "primary"}],
"timeout": 24,
"timeout_unit": "hour",
},
}
]
}
# Should not raise any exception
workflow_service.validate_graph_structure(graph)
def test_validate_graph_structure_empty_graph(self, workflow_service):
"""Test validation of empty graph."""
graph = {}
# Should not raise any exception
workflow_service.validate_graph_structure(graph)
def test_validate_graph_structure_no_nodes(self, workflow_service):
"""Test validation of graph with no nodes."""
graph = {"nodes": []}
# Should not raise any exception
workflow_service.validate_graph_structure(graph)
def test_validate_graph_structure_non_human_input_node(self, workflow_service):
"""Test validation ignores non-HumanInput nodes."""
graph = {"nodes": [{"id": "node-1", "data": {"type": "start", "title": "Start"}}]}
# Should not raise any exception
workflow_service.validate_graph_structure(graph)
def test_validate_human_input_node_data_invalid_delivery_method_type(self, workflow_service):
"""Test validation fails with invalid delivery method type."""
graph = {
"nodes": [
{
"id": "node-1",
"data": {
"type": "human_input",
"title": "Human Input",
"delivery_methods": [{"type": "invalid_type", "enabled": True, "config": {}}],
"form_content": "Please provide your input",
"inputs": [],
"user_actions": [],
"timeout": 24,
"timeout_unit": "hour",
},
}
]
}
with pytest.raises(ValueError, match="Invalid HumanInput node data"):
workflow_service.validate_graph_structure(graph)
def test_validate_human_input_node_data_invalid_form_input_type(self, workflow_service):
"""Test validation fails with invalid form input type."""
graph = {
"nodes": [
{
"id": "node-1",
"data": {
"type": "human_input",
"title": "Human Input",
"delivery_methods": [{"type": "webapp", "enabled": True, "config": {}}],
"form_content": "Please provide your input",
"inputs": [{"type": "invalid-input-type", "output_variable_name": "user_input"}],
"user_actions": [],
"timeout": 24,
"timeout_unit": "hour",
},
}
]
}
with pytest.raises(ValueError, match="Invalid HumanInput node data"):
workflow_service.validate_graph_structure(graph)
def test_validate_human_input_node_data_missing_required_fields(self, workflow_service):
"""Test validation fails with missing required fields."""
graph = {
"nodes": [
{
"id": "node-1",
"data": {
"type": "human_input",
# Missing required fields like title
"delivery_methods": [],
"form_content": "",
"inputs": [],
"user_actions": [],
},
}
]
}
with pytest.raises(ValueError, match="Invalid HumanInput node data"):
workflow_service.validate_graph_structure(graph)
def test_validate_human_input_node_data_invalid_timeout_unit(self, workflow_service):
"""Test validation fails with invalid timeout unit."""
graph = {
"nodes": [
{
"id": "node-1",
"data": {
"type": "human_input",
"title": "Human Input",
"delivery_methods": [{"type": "webapp", "enabled": True, "config": {}}],
"form_content": "Please provide your input",
"inputs": [],
"user_actions": [],
"timeout": 24,
"timeout_unit": "invalid_unit",
},
}
]
}
with pytest.raises(ValueError, match="Invalid HumanInput node data"):
workflow_service.validate_graph_structure(graph)
def test_validate_human_input_node_data_invalid_button_style(self, workflow_service):
"""Test validation fails with invalid button style."""
graph = {
"nodes": [
{
"id": "node-1",
"data": {
"type": "human_input",
"title": "Human Input",
"delivery_methods": [{"type": "webapp", "enabled": True, "config": {}}],
"form_content": "Please provide your input",
"inputs": [],
"user_actions": [{"id": "submit", "title": "Submit", "button_style": "invalid_style"}],
"timeout": 24,
"timeout_unit": "hour",
},
}
]
}
with pytest.raises(ValueError, match="Invalid HumanInput node data"):
workflow_service.validate_graph_structure(graph)
def test_validate_human_input_node_data_email_delivery_config(self, workflow_service):
"""Test validation of HumanInput node with email delivery configuration."""
graph = {
"nodes": [
{
"id": "node-1",
"data": {
"type": "human_input",
"title": "Human Input",
"delivery_methods": [
{
"type": "email",
"enabled": True,
"config": {
"recipients": {
"whole_workspace": False,
"items": [{"type": "external", "email": "user@example.com"}],
},
"subject": "Input Required",
"body": "Please provide your input",
},
}
],
"form_content": "Please provide your input",
"inputs": [
{
"type": "paragraph",
"output_variable_name": "feedback",
"placeholder": {"type": "variable", "selector": ["node", "output"]},
}
],
"user_actions": [
{"id": "approve", "title": "Approve", "button_style": "accent"},
{"id": "reject", "title": "Reject", "button_style": "ghost"},
],
"timeout": 7,
"timeout_unit": "day",
},
}
]
}
# Should not raise any exception
workflow_service.validate_graph_structure(graph)
def test_validate_human_input_node_data_invalid_email_recipient(self, workflow_service):
"""Test validation fails with invalid email recipient."""
graph = {
"nodes": [
{
"id": "node-1",
"data": {
"type": "human_input",
"title": "Human Input",
"delivery_methods": [
{
"type": "email",
"enabled": True,
"config": {
"recipients": {
"whole_workspace": False,
"items": [{"type": "invalid_recipient_type", "email": "user@example.com"}],
},
"subject": "Input Required",
"body": "Please provide your input",
},
}
],
"form_content": "Please provide your input",
"inputs": [],
"user_actions": [],
"timeout": 24,
"timeout_unit": "hour",
},
}
]
}
with pytest.raises(ValueError, match="Invalid HumanInput node data"):
workflow_service.validate_graph_structure(graph)
def test_validate_human_input_node_data_multiple_nodes_mixed_valid_invalid(self, workflow_service):
"""Test validation with multiple nodes where some are valid and some invalid."""
graph = {
"nodes": [
{"id": "node-1", "data": {"type": "start", "title": "Start"}},
{
"id": "node-2",
"data": {
"type": "human_input",
"title": "Valid Human Input",
"delivery_methods": [{"type": "webapp", "enabled": True, "config": {}}],
"form_content": "Valid input",
"inputs": [],
"user_actions": [],
"timeout": 24,
"timeout_unit": "hour",
},
},
{
"id": "node-3",
"data": {
"type": "human_input",
"title": "Invalid Human Input",
"delivery_methods": [{"type": "invalid_method", "enabled": True}],
"form_content": "Invalid input",
"inputs": [],
"user_actions": [],
"timeout": 24,
"timeout_unit": "hour",
},
},
]
}
with pytest.raises(ValueError, match="Invalid HumanInput node data"):
workflow_service.validate_graph_structure(graph)