mirror of https://github.com/langgenius/dify.git
add unit tests for template transform node (#28595)
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
This commit is contained in:
parent
ddc5cbe865
commit
b2a7cec644
|
|
@ -0,0 +1 @@
|
|||
|
||||
|
|
@ -0,0 +1,225 @@
|
|||
import pytest
|
||||
from pydantic import ValidationError
|
||||
|
||||
from core.workflow.enums import ErrorStrategy
|
||||
from core.workflow.nodes.template_transform.entities import TemplateTransformNodeData
|
||||
|
||||
|
||||
class TestTemplateTransformNodeData:
|
||||
"""Test suite for TemplateTransformNodeData entity."""
|
||||
|
||||
def test_valid_template_transform_node_data(self):
|
||||
"""Test creating valid TemplateTransformNodeData."""
|
||||
data = {
|
||||
"title": "Template Transform",
|
||||
"desc": "Transform data using Jinja2 template",
|
||||
"variables": [
|
||||
{"variable": "name", "value_selector": ["sys", "user_name"]},
|
||||
{"variable": "age", "value_selector": ["sys", "user_age"]},
|
||||
],
|
||||
"template": "Hello {{ name }}, you are {{ age }} years old!",
|
||||
}
|
||||
|
||||
node_data = TemplateTransformNodeData.model_validate(data)
|
||||
|
||||
assert node_data.title == "Template Transform"
|
||||
assert node_data.desc == "Transform data using Jinja2 template"
|
||||
assert len(node_data.variables) == 2
|
||||
assert node_data.variables[0].variable == "name"
|
||||
assert node_data.variables[0].value_selector == ["sys", "user_name"]
|
||||
assert node_data.variables[1].variable == "age"
|
||||
assert node_data.variables[1].value_selector == ["sys", "user_age"]
|
||||
assert node_data.template == "Hello {{ name }}, you are {{ age }} years old!"
|
||||
|
||||
def test_template_transform_node_data_with_empty_variables(self):
|
||||
"""Test TemplateTransformNodeData with no variables."""
|
||||
data = {
|
||||
"title": "Static Template",
|
||||
"variables": [],
|
||||
"template": "This is a static template with no variables.",
|
||||
}
|
||||
|
||||
node_data = TemplateTransformNodeData.model_validate(data)
|
||||
|
||||
assert node_data.title == "Static Template"
|
||||
assert len(node_data.variables) == 0
|
||||
assert node_data.template == "This is a static template with no variables."
|
||||
|
||||
def test_template_transform_node_data_with_complex_template(self):
|
||||
"""Test TemplateTransformNodeData with complex Jinja2 template."""
|
||||
data = {
|
||||
"title": "Complex Template",
|
||||
"variables": [
|
||||
{"variable": "items", "value_selector": ["sys", "item_list"]},
|
||||
{"variable": "total", "value_selector": ["sys", "total_count"]},
|
||||
],
|
||||
"template": (
|
||||
"{% for item in items %}{{ item }}{% if not loop.last %}, {% endif %}{% endfor %}. Total: {{ total }}"
|
||||
),
|
||||
}
|
||||
|
||||
node_data = TemplateTransformNodeData.model_validate(data)
|
||||
|
||||
assert node_data.title == "Complex Template"
|
||||
assert len(node_data.variables) == 2
|
||||
assert "{% for item in items %}" in node_data.template
|
||||
assert "{{ total }}" in node_data.template
|
||||
|
||||
def test_template_transform_node_data_with_error_strategy(self):
|
||||
"""Test TemplateTransformNodeData with error handling strategy."""
|
||||
data = {
|
||||
"title": "Template with Error Handling",
|
||||
"variables": [{"variable": "value", "value_selector": ["sys", "input"]}],
|
||||
"template": "{{ value }}",
|
||||
"error_strategy": "fail-branch",
|
||||
}
|
||||
|
||||
node_data = TemplateTransformNodeData.model_validate(data)
|
||||
|
||||
assert node_data.error_strategy == ErrorStrategy.FAIL_BRANCH
|
||||
|
||||
def test_template_transform_node_data_with_retry_config(self):
|
||||
"""Test TemplateTransformNodeData with retry configuration."""
|
||||
data = {
|
||||
"title": "Template with Retry",
|
||||
"variables": [{"variable": "data", "value_selector": ["sys", "data"]}],
|
||||
"template": "{{ data }}",
|
||||
"retry_config": {"enabled": True, "max_retries": 3, "retry_interval": 1000},
|
||||
}
|
||||
|
||||
node_data = TemplateTransformNodeData.model_validate(data)
|
||||
|
||||
assert node_data.retry_config.enabled is True
|
||||
assert node_data.retry_config.max_retries == 3
|
||||
assert node_data.retry_config.retry_interval == 1000
|
||||
|
||||
def test_template_transform_node_data_missing_required_fields(self):
|
||||
"""Test that missing required fields raises ValidationError."""
|
||||
data = {
|
||||
"title": "Incomplete Template",
|
||||
# Missing 'variables' and 'template'
|
||||
}
|
||||
|
||||
with pytest.raises(ValidationError) as exc_info:
|
||||
TemplateTransformNodeData.model_validate(data)
|
||||
|
||||
errors = exc_info.value.errors()
|
||||
assert len(errors) >= 2
|
||||
error_fields = {error["loc"][0] for error in errors}
|
||||
assert "variables" in error_fields
|
||||
assert "template" in error_fields
|
||||
|
||||
def test_template_transform_node_data_invalid_variable_selector(self):
|
||||
"""Test that invalid variable selector format raises ValidationError."""
|
||||
data = {
|
||||
"title": "Invalid Variable",
|
||||
"variables": [
|
||||
{"variable": "name", "value_selector": "invalid_format"} # Should be list
|
||||
],
|
||||
"template": "{{ name }}",
|
||||
}
|
||||
|
||||
with pytest.raises(ValidationError):
|
||||
TemplateTransformNodeData.model_validate(data)
|
||||
|
||||
def test_template_transform_node_data_with_default_value_dict(self):
|
||||
"""Test TemplateTransformNodeData with default value dictionary."""
|
||||
data = {
|
||||
"title": "Template with Defaults",
|
||||
"variables": [
|
||||
{"variable": "name", "value_selector": ["sys", "user_name"]},
|
||||
{"variable": "greeting", "value_selector": ["sys", "greeting"]},
|
||||
],
|
||||
"template": "{{ greeting }} {{ name }}!",
|
||||
"default_value_dict": {"greeting": "Hello", "name": "Guest"},
|
||||
}
|
||||
|
||||
node_data = TemplateTransformNodeData.model_validate(data)
|
||||
|
||||
assert node_data.default_value_dict == {"greeting": "Hello", "name": "Guest"}
|
||||
|
||||
def test_template_transform_node_data_with_nested_selectors(self):
|
||||
"""Test TemplateTransformNodeData with nested variable selectors."""
|
||||
data = {
|
||||
"title": "Nested Selectors",
|
||||
"variables": [
|
||||
{"variable": "user_info", "value_selector": ["sys", "user", "profile", "name"]},
|
||||
{"variable": "settings", "value_selector": ["sys", "config", "app", "theme"]},
|
||||
],
|
||||
"template": "User: {{ user_info }}, Theme: {{ settings }}",
|
||||
}
|
||||
|
||||
node_data = TemplateTransformNodeData.model_validate(data)
|
||||
|
||||
assert len(node_data.variables) == 2
|
||||
assert node_data.variables[0].value_selector == ["sys", "user", "profile", "name"]
|
||||
assert node_data.variables[1].value_selector == ["sys", "config", "app", "theme"]
|
||||
|
||||
def test_template_transform_node_data_with_multiline_template(self):
|
||||
"""Test TemplateTransformNodeData with multiline template."""
|
||||
data = {
|
||||
"title": "Multiline Template",
|
||||
"variables": [
|
||||
{"variable": "title", "value_selector": ["sys", "title"]},
|
||||
{"variable": "content", "value_selector": ["sys", "content"]},
|
||||
],
|
||||
"template": """
|
||||
# {{ title }}
|
||||
|
||||
{{ content }}
|
||||
|
||||
---
|
||||
Generated by Template Transform Node
|
||||
""",
|
||||
}
|
||||
|
||||
node_data = TemplateTransformNodeData.model_validate(data)
|
||||
|
||||
assert "# {{ title }}" in node_data.template
|
||||
assert "{{ content }}" in node_data.template
|
||||
assert "Generated by Template Transform Node" in node_data.template
|
||||
|
||||
def test_template_transform_node_data_serialization(self):
|
||||
"""Test that TemplateTransformNodeData can be serialized and deserialized."""
|
||||
original_data = {
|
||||
"title": "Serialization Test",
|
||||
"desc": "Test serialization",
|
||||
"variables": [{"variable": "test", "value_selector": ["sys", "test"]}],
|
||||
"template": "{{ test }}",
|
||||
}
|
||||
|
||||
node_data = TemplateTransformNodeData.model_validate(original_data)
|
||||
serialized = node_data.model_dump()
|
||||
deserialized = TemplateTransformNodeData.model_validate(serialized)
|
||||
|
||||
assert deserialized.title == node_data.title
|
||||
assert deserialized.desc == node_data.desc
|
||||
assert len(deserialized.variables) == len(node_data.variables)
|
||||
assert deserialized.template == node_data.template
|
||||
|
||||
def test_template_transform_node_data_with_special_characters(self):
|
||||
"""Test TemplateTransformNodeData with special characters in template."""
|
||||
data = {
|
||||
"title": "Special Characters",
|
||||
"variables": [{"variable": "text", "value_selector": ["sys", "input"]}],
|
||||
"template": "Special: {{ text }} | Symbols: @#$%^&*() | Unicode: 你好 🎉",
|
||||
}
|
||||
|
||||
node_data = TemplateTransformNodeData.model_validate(data)
|
||||
|
||||
assert "@#$%^&*()" in node_data.template
|
||||
assert "你好" in node_data.template
|
||||
assert "🎉" in node_data.template
|
||||
|
||||
def test_template_transform_node_data_empty_template(self):
|
||||
"""Test TemplateTransformNodeData with empty template string."""
|
||||
data = {
|
||||
"title": "Empty Template",
|
||||
"variables": [],
|
||||
"template": "",
|
||||
}
|
||||
|
||||
node_data = TemplateTransformNodeData.model_validate(data)
|
||||
|
||||
assert node_data.template == ""
|
||||
assert len(node_data.variables) == 0
|
||||
|
|
@ -0,0 +1,414 @@
|
|||
from unittest.mock import MagicMock, patch
|
||||
|
||||
import pytest
|
||||
from core.workflow.graph_engine.entities.graph import Graph
|
||||
from core.workflow.graph_engine.entities.graph_init_params import GraphInitParams
|
||||
from core.workflow.graph_engine.entities.graph_runtime_state import GraphRuntimeState
|
||||
|
||||
from core.helper.code_executor.code_executor import CodeExecutionError
|
||||
from core.workflow.enums import ErrorStrategy, NodeType, WorkflowNodeExecutionStatus
|
||||
from core.workflow.nodes.template_transform.template_transform_node import TemplateTransformNode
|
||||
from models.workflow import WorkflowType
|
||||
|
||||
|
||||
class TestTemplateTransformNode:
|
||||
"""Comprehensive test suite for TemplateTransformNode."""
|
||||
|
||||
@pytest.fixture
|
||||
def mock_graph_runtime_state(self):
|
||||
"""Create a mock GraphRuntimeState with variable pool."""
|
||||
mock_state = MagicMock(spec=GraphRuntimeState)
|
||||
mock_variable_pool = MagicMock()
|
||||
mock_state.variable_pool = mock_variable_pool
|
||||
return mock_state
|
||||
|
||||
@pytest.fixture
|
||||
def mock_graph(self):
|
||||
"""Create a mock Graph."""
|
||||
return MagicMock(spec=Graph)
|
||||
|
||||
@pytest.fixture
|
||||
def graph_init_params(self):
|
||||
"""Create a mock GraphInitParams."""
|
||||
return GraphInitParams(
|
||||
tenant_id="test_tenant",
|
||||
app_id="test_app",
|
||||
workflow_type=WorkflowType.WORKFLOW,
|
||||
workflow_id="test_workflow",
|
||||
graph_config={},
|
||||
user_id="test_user",
|
||||
user_from="test",
|
||||
invoke_from="test",
|
||||
call_depth=0,
|
||||
)
|
||||
|
||||
@pytest.fixture
|
||||
def basic_node_data(self):
|
||||
"""Create basic node data for testing."""
|
||||
return {
|
||||
"title": "Template Transform",
|
||||
"desc": "Transform data using template",
|
||||
"variables": [
|
||||
{"variable": "name", "value_selector": ["sys", "user_name"]},
|
||||
{"variable": "age", "value_selector": ["sys", "user_age"]},
|
||||
],
|
||||
"template": "Hello {{ name }}, you are {{ age }} years old!",
|
||||
}
|
||||
|
||||
def test_node_initialization(self, basic_node_data, mock_graph, mock_graph_runtime_state, graph_init_params):
|
||||
"""Test that TemplateTransformNode initializes correctly."""
|
||||
node = TemplateTransformNode(
|
||||
id="test_node",
|
||||
config=basic_node_data,
|
||||
graph_init_params=graph_init_params,
|
||||
graph=mock_graph,
|
||||
graph_runtime_state=mock_graph_runtime_state,
|
||||
)
|
||||
|
||||
assert node.node_type == NodeType.TEMPLATE_TRANSFORM
|
||||
assert node._node_data.title == "Template Transform"
|
||||
assert len(node._node_data.variables) == 2
|
||||
assert node._node_data.template == "Hello {{ name }}, you are {{ age }} years old!"
|
||||
|
||||
def test_get_title(self, basic_node_data, mock_graph, mock_graph_runtime_state, graph_init_params):
|
||||
"""Test _get_title method."""
|
||||
node = TemplateTransformNode(
|
||||
id="test_node",
|
||||
config=basic_node_data,
|
||||
graph_init_params=graph_init_params,
|
||||
graph=mock_graph,
|
||||
graph_runtime_state=mock_graph_runtime_state,
|
||||
)
|
||||
|
||||
assert node._get_title() == "Template Transform"
|
||||
|
||||
def test_get_description(self, basic_node_data, mock_graph, mock_graph_runtime_state, graph_init_params):
|
||||
"""Test _get_description method."""
|
||||
node = TemplateTransformNode(
|
||||
id="test_node",
|
||||
config=basic_node_data,
|
||||
graph_init_params=graph_init_params,
|
||||
graph=mock_graph,
|
||||
graph_runtime_state=mock_graph_runtime_state,
|
||||
)
|
||||
|
||||
assert node._get_description() == "Transform data using template"
|
||||
|
||||
def test_get_error_strategy(self, mock_graph, mock_graph_runtime_state, graph_init_params):
|
||||
"""Test _get_error_strategy method."""
|
||||
node_data = {
|
||||
"title": "Test",
|
||||
"variables": [],
|
||||
"template": "test",
|
||||
"error_strategy": "fail-branch",
|
||||
}
|
||||
|
||||
node = TemplateTransformNode(
|
||||
id="test_node",
|
||||
config=node_data,
|
||||
graph_init_params=graph_init_params,
|
||||
graph=mock_graph,
|
||||
graph_runtime_state=mock_graph_runtime_state,
|
||||
)
|
||||
|
||||
assert node._get_error_strategy() == ErrorStrategy.FAIL_BRANCH
|
||||
|
||||
def test_get_default_config(self):
|
||||
"""Test get_default_config class method."""
|
||||
config = TemplateTransformNode.get_default_config()
|
||||
|
||||
assert config["type"] == "template-transform"
|
||||
assert "config" in config
|
||||
assert "variables" in config["config"]
|
||||
assert "template" in config["config"]
|
||||
assert config["config"]["template"] == "{{ arg1 }}"
|
||||
|
||||
def test_version(self):
|
||||
"""Test version class method."""
|
||||
assert TemplateTransformNode.version() == "1"
|
||||
|
||||
@patch("core.workflow.nodes.template_transform.template_transform_node.CodeExecutor.execute_workflow_code_template")
|
||||
def test_run_simple_template(
|
||||
self, mock_execute, basic_node_data, mock_graph, mock_graph_runtime_state, graph_init_params
|
||||
):
|
||||
"""Test _run with simple template transformation."""
|
||||
# Setup mock variable pool
|
||||
mock_name_value = MagicMock()
|
||||
mock_name_value.to_object.return_value = "Alice"
|
||||
mock_age_value = MagicMock()
|
||||
mock_age_value.to_object.return_value = 30
|
||||
|
||||
variable_map = {
|
||||
("sys", "user_name"): mock_name_value,
|
||||
("sys", "user_age"): mock_age_value,
|
||||
}
|
||||
mock_graph_runtime_state.variable_pool.get.side_effect = lambda selector: variable_map.get(tuple(selector))
|
||||
|
||||
# Setup mock executor
|
||||
mock_execute.return_value = {"result": "Hello Alice, you are 30 years old!"}
|
||||
|
||||
node = TemplateTransformNode(
|
||||
id="test_node",
|
||||
config=basic_node_data,
|
||||
graph_init_params=graph_init_params,
|
||||
graph=mock_graph,
|
||||
graph_runtime_state=mock_graph_runtime_state,
|
||||
)
|
||||
|
||||
result = node._run()
|
||||
|
||||
assert result.status == WorkflowNodeExecutionStatus.SUCCEEDED
|
||||
assert result.outputs["output"] == "Hello Alice, you are 30 years old!"
|
||||
assert result.inputs["name"] == "Alice"
|
||||
assert result.inputs["age"] == 30
|
||||
|
||||
@patch("core.workflow.nodes.template_transform.template_transform_node.CodeExecutor.execute_workflow_code_template")
|
||||
def test_run_with_none_values(self, mock_execute, mock_graph, mock_graph_runtime_state, graph_init_params):
|
||||
"""Test _run with None variable values."""
|
||||
node_data = {
|
||||
"title": "Test",
|
||||
"variables": [{"variable": "value", "value_selector": ["sys", "missing"]}],
|
||||
"template": "Value: {{ value }}",
|
||||
}
|
||||
|
||||
mock_graph_runtime_state.variable_pool.get.return_value = None
|
||||
mock_execute.return_value = {"result": "Value: "}
|
||||
|
||||
node = TemplateTransformNode(
|
||||
id="test_node",
|
||||
config=node_data,
|
||||
graph_init_params=graph_init_params,
|
||||
graph=mock_graph,
|
||||
graph_runtime_state=mock_graph_runtime_state,
|
||||
)
|
||||
|
||||
result = node._run()
|
||||
|
||||
assert result.status == WorkflowNodeExecutionStatus.SUCCEEDED
|
||||
assert result.inputs["value"] is None
|
||||
|
||||
@patch("core.workflow.nodes.template_transform.template_transform_node.CodeExecutor.execute_workflow_code_template")
|
||||
def test_run_with_code_execution_error(
|
||||
self, mock_execute, basic_node_data, mock_graph, mock_graph_runtime_state, graph_init_params
|
||||
):
|
||||
"""Test _run when code execution fails."""
|
||||
mock_graph_runtime_state.variable_pool.get.return_value = MagicMock()
|
||||
mock_execute.side_effect = CodeExecutionError("Template syntax error")
|
||||
|
||||
node = TemplateTransformNode(
|
||||
id="test_node",
|
||||
config=basic_node_data,
|
||||
graph_init_params=graph_init_params,
|
||||
graph=mock_graph,
|
||||
graph_runtime_state=mock_graph_runtime_state,
|
||||
)
|
||||
|
||||
result = node._run()
|
||||
|
||||
assert result.status == WorkflowNodeExecutionStatus.FAILED
|
||||
assert "Template syntax error" in result.error
|
||||
|
||||
@patch("core.workflow.nodes.template_transform.template_transform_node.CodeExecutor.execute_workflow_code_template")
|
||||
@patch("core.workflow.nodes.template_transform.template_transform_node.MAX_TEMPLATE_TRANSFORM_OUTPUT_LENGTH", 10)
|
||||
def test_run_output_length_exceeds_limit(
|
||||
self, mock_execute, basic_node_data, mock_graph, mock_graph_runtime_state, graph_init_params
|
||||
):
|
||||
"""Test _run when output exceeds maximum length."""
|
||||
mock_graph_runtime_state.variable_pool.get.return_value = MagicMock()
|
||||
mock_execute.return_value = {"result": "This is a very long output that exceeds the limit"}
|
||||
|
||||
node = TemplateTransformNode(
|
||||
id="test_node",
|
||||
config=basic_node_data,
|
||||
graph_init_params=graph_init_params,
|
||||
graph=mock_graph,
|
||||
graph_runtime_state=mock_graph_runtime_state,
|
||||
)
|
||||
|
||||
result = node._run()
|
||||
|
||||
assert result.status == WorkflowNodeExecutionStatus.FAILED
|
||||
assert "Output length exceeds" in result.error
|
||||
|
||||
@patch("core.workflow.nodes.template_transform.template_transform_node.CodeExecutor.execute_workflow_code_template")
|
||||
def test_run_with_complex_jinja2_template(
|
||||
self, mock_execute, mock_graph, mock_graph_runtime_state, graph_init_params
|
||||
):
|
||||
"""Test _run with complex Jinja2 template including loops and conditions."""
|
||||
node_data = {
|
||||
"title": "Complex Template",
|
||||
"variables": [
|
||||
{"variable": "items", "value_selector": ["sys", "items"]},
|
||||
{"variable": "show_total", "value_selector": ["sys", "show_total"]},
|
||||
],
|
||||
"template": (
|
||||
"{% for item in items %}{{ item }}{% if not loop.last %}, {% endif %}{% endfor %}"
|
||||
"{% if show_total %} (Total: {{ items|length }}){% endif %}"
|
||||
),
|
||||
}
|
||||
|
||||
mock_items = MagicMock()
|
||||
mock_items.to_object.return_value = ["apple", "banana", "orange"]
|
||||
mock_show_total = MagicMock()
|
||||
mock_show_total.to_object.return_value = True
|
||||
|
||||
variable_map = {
|
||||
("sys", "items"): mock_items,
|
||||
("sys", "show_total"): mock_show_total,
|
||||
}
|
||||
mock_graph_runtime_state.variable_pool.get.side_effect = lambda selector: variable_map.get(tuple(selector))
|
||||
mock_execute.return_value = {"result": "apple, banana, orange (Total: 3)"}
|
||||
|
||||
node = TemplateTransformNode(
|
||||
id="test_node",
|
||||
config=node_data,
|
||||
graph_init_params=graph_init_params,
|
||||
graph=mock_graph,
|
||||
graph_runtime_state=mock_graph_runtime_state,
|
||||
)
|
||||
|
||||
result = node._run()
|
||||
|
||||
assert result.status == WorkflowNodeExecutionStatus.SUCCEEDED
|
||||
assert result.outputs["output"] == "apple, banana, orange (Total: 3)"
|
||||
|
||||
def test_extract_variable_selector_to_variable_mapping(self):
|
||||
"""Test _extract_variable_selector_to_variable_mapping class method."""
|
||||
node_data = {
|
||||
"title": "Test",
|
||||
"variables": [
|
||||
{"variable": "var1", "value_selector": ["sys", "input1"]},
|
||||
{"variable": "var2", "value_selector": ["sys", "input2"]},
|
||||
],
|
||||
"template": "{{ var1 }} {{ var2 }}",
|
||||
}
|
||||
|
||||
mapping = TemplateTransformNode._extract_variable_selector_to_variable_mapping(
|
||||
graph_config={}, node_id="node_123", node_data=node_data
|
||||
)
|
||||
|
||||
assert "node_123.var1" in mapping
|
||||
assert "node_123.var2" in mapping
|
||||
assert mapping["node_123.var1"] == ["sys", "input1"]
|
||||
assert mapping["node_123.var2"] == ["sys", "input2"]
|
||||
|
||||
@patch("core.workflow.nodes.template_transform.template_transform_node.CodeExecutor.execute_workflow_code_template")
|
||||
def test_run_with_empty_variables(self, mock_execute, mock_graph, mock_graph_runtime_state, graph_init_params):
|
||||
"""Test _run with no variables (static template)."""
|
||||
node_data = {
|
||||
"title": "Static Template",
|
||||
"variables": [],
|
||||
"template": "This is a static message.",
|
||||
}
|
||||
|
||||
mock_execute.return_value = {"result": "This is a static message."}
|
||||
|
||||
node = TemplateTransformNode(
|
||||
id="test_node",
|
||||
config=node_data,
|
||||
graph_init_params=graph_init_params,
|
||||
graph=mock_graph,
|
||||
graph_runtime_state=mock_graph_runtime_state,
|
||||
)
|
||||
|
||||
result = node._run()
|
||||
|
||||
assert result.status == WorkflowNodeExecutionStatus.SUCCEEDED
|
||||
assert result.outputs["output"] == "This is a static message."
|
||||
assert result.inputs == {}
|
||||
|
||||
@patch("core.workflow.nodes.template_transform.template_transform_node.CodeExecutor.execute_workflow_code_template")
|
||||
def test_run_with_numeric_values(self, mock_execute, mock_graph, mock_graph_runtime_state, graph_init_params):
|
||||
"""Test _run with numeric variable values."""
|
||||
node_data = {
|
||||
"title": "Numeric Template",
|
||||
"variables": [
|
||||
{"variable": "price", "value_selector": ["sys", "price"]},
|
||||
{"variable": "quantity", "value_selector": ["sys", "quantity"]},
|
||||
],
|
||||
"template": "Total: ${{ price * quantity }}",
|
||||
}
|
||||
|
||||
mock_price = MagicMock()
|
||||
mock_price.to_object.return_value = 10.5
|
||||
mock_quantity = MagicMock()
|
||||
mock_quantity.to_object.return_value = 3
|
||||
|
||||
variable_map = {
|
||||
("sys", "price"): mock_price,
|
||||
("sys", "quantity"): mock_quantity,
|
||||
}
|
||||
mock_graph_runtime_state.variable_pool.get.side_effect = lambda selector: variable_map.get(tuple(selector))
|
||||
mock_execute.return_value = {"result": "Total: $31.5"}
|
||||
|
||||
node = TemplateTransformNode(
|
||||
id="test_node",
|
||||
config=node_data,
|
||||
graph_init_params=graph_init_params,
|
||||
graph=mock_graph,
|
||||
graph_runtime_state=mock_graph_runtime_state,
|
||||
)
|
||||
|
||||
result = node._run()
|
||||
|
||||
assert result.status == WorkflowNodeExecutionStatus.SUCCEEDED
|
||||
assert result.outputs["output"] == "Total: $31.5"
|
||||
|
||||
@patch("core.workflow.nodes.template_transform.template_transform_node.CodeExecutor.execute_workflow_code_template")
|
||||
def test_run_with_dict_values(self, mock_execute, mock_graph, mock_graph_runtime_state, graph_init_params):
|
||||
"""Test _run with dictionary variable values."""
|
||||
node_data = {
|
||||
"title": "Dict Template",
|
||||
"variables": [{"variable": "user", "value_selector": ["sys", "user_data"]}],
|
||||
"template": "Name: {{ user.name }}, Email: {{ user.email }}",
|
||||
}
|
||||
|
||||
mock_user = MagicMock()
|
||||
mock_user.to_object.return_value = {"name": "John Doe", "email": "john@example.com"}
|
||||
|
||||
mock_graph_runtime_state.variable_pool.get.return_value = mock_user
|
||||
mock_execute.return_value = {"result": "Name: John Doe, Email: john@example.com"}
|
||||
|
||||
node = TemplateTransformNode(
|
||||
id="test_node",
|
||||
config=node_data,
|
||||
graph_init_params=graph_init_params,
|
||||
graph=mock_graph,
|
||||
graph_runtime_state=mock_graph_runtime_state,
|
||||
)
|
||||
|
||||
result = node._run()
|
||||
|
||||
assert result.status == WorkflowNodeExecutionStatus.SUCCEEDED
|
||||
assert "John Doe" in result.outputs["output"]
|
||||
assert "john@example.com" in result.outputs["output"]
|
||||
|
||||
@patch("core.workflow.nodes.template_transform.template_transform_node.CodeExecutor.execute_workflow_code_template")
|
||||
def test_run_with_list_values(self, mock_execute, mock_graph, mock_graph_runtime_state, graph_init_params):
|
||||
"""Test _run with list variable values."""
|
||||
node_data = {
|
||||
"title": "List Template",
|
||||
"variables": [{"variable": "tags", "value_selector": ["sys", "tags"]}],
|
||||
"template": "Tags: {% for tag in tags %}#{{ tag }} {% endfor %}",
|
||||
}
|
||||
|
||||
mock_tags = MagicMock()
|
||||
mock_tags.to_object.return_value = ["python", "ai", "workflow"]
|
||||
|
||||
mock_graph_runtime_state.variable_pool.get.return_value = mock_tags
|
||||
mock_execute.return_value = {"result": "Tags: #python #ai #workflow "}
|
||||
|
||||
node = TemplateTransformNode(
|
||||
id="test_node",
|
||||
config=node_data,
|
||||
graph_init_params=graph_init_params,
|
||||
graph=mock_graph,
|
||||
graph_runtime_state=mock_graph_runtime_state,
|
||||
)
|
||||
|
||||
result = node._run()
|
||||
|
||||
assert result.status == WorkflowNodeExecutionStatus.SUCCEEDED
|
||||
assert "#python" in result.outputs["output"]
|
||||
assert "#ai" in result.outputs["output"]
|
||||
assert "#workflow" in result.outputs["output"]
|
||||
Loading…
Reference in New Issue