mirror of
https://github.com/langgenius/dify.git
synced 2026-05-06 02:18:08 +08:00
WIP
This commit is contained in:
@ -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)
|
||||
|
||||
Reference in New Issue
Block a user