9753b31c7e
CI / quality (push) Successful in 36s
CI / lint (push) Successful in 38s
CI / typecheck (push) Successful in 49s
CI / security (push) Successful in 51s
CI / integration_tests (push) Successful in 55s
CI / unit_tests (push) Successful in 3m35s
CI / build (push) Successful in 33s
CI / coverage (push) Successful in 3m36s
CI / status-check (push) Successful in 3s
Add 13 BDD scenarios covering previously uncovered code paths: - SAFE_BUILTINS validation (sandbox.py: 0% → 100%) - ConfigurationError re-raise path (config.py: 99.3% → 100%) - CLI hello/main functions (cli.py: 72.7% → 90.9%) - GraphState message truncation (state.py: 98.7% → 100%) - ProgressBarManager update/context rendering (progress.py: 0% → 87.7%) - MessageRouter regex/exact/contains routing (message_router.py: 0% → 59.4%) - RoutingAdapter parse_routing_command (routing_adapter.py) - DynamicRouterNode pattern-based routing (dynamic_router.py) - EnhancedTemplateRegistry unknown template type (enhanced_registry.py: 99.2%) - CompositeAgent null-graph error path (composite.py: 97.8% → 98.6%) Cover routing_adapter.py (17% → 100%): all GOTO/ROUTE patterns, create_routing_node, create_conditional_router, dynamic config conversion. Cover dynamic_router.py (21% → 87%): execute with empty/dict/string messages, extract_message with colon parsing, config creation, graph extension with edge generation. Cover message_router.py (59% → 78%): regex, exact, contains, prefix, suffix match types, invalid regex handling, non-string message, set_state. Exercise Node._prepare_conversation_history with invalid configs, _runtime error paths, _execute_message_router with rules, _execute_agent with current_message and metadata propagation, _execute_function with dynamic_router, and _execute_conditional with content_contains/content_not_contains/content_starts_with and custom condition types. Improves nodes.py from 71.3% to 72.5%. Exercise PureGraphConfig, PureLangGraph init with dict/config, RxPyLangGraphBridge registration/connection/lookup, ReactiveStreamRouter operator creation and condition functions, ReactiveConfigParser config/route/graph parsing, ToolAgent tool execution with JSON, space-separated, single, file_read, progress_bar invocations, and ReactiveCleverAgentsApp init/dispose/visualization.
748 lines
26 KiB
Python
748 lines
26 KiB
Python
"""
|
|
Step definitions for Stream Template Operator Processing BDD tests.
|
|
"""
|
|
|
|
import copy
|
|
from typing import Any, Dict
|
|
|
|
from behave import given, then, when
|
|
|
|
from cleveractors.templates.base import (
|
|
BaseTemplate,
|
|
ComponentReference,
|
|
InstantiationContext,
|
|
TemplateType,
|
|
)
|
|
from cleveractors.templates.stream_templates import StreamTemplate
|
|
|
|
|
|
# Mock implementations for testing
|
|
class MockTemplateRegistry:
|
|
"""Mock template registry for testing."""
|
|
|
|
def __init__(self):
|
|
self.templates = {}
|
|
self.calls = []
|
|
|
|
def get_template(self, template_type: TemplateType, name: str) -> BaseTemplate:
|
|
self.calls.append(("get_template", template_type, name))
|
|
return self.templates.get(f"{template_type.value}:{name}")
|
|
|
|
def instantiate(
|
|
self,
|
|
template_type: TemplateType,
|
|
name: str,
|
|
params: Dict[str, Any],
|
|
context: InstantiationContext = None,
|
|
) -> Any:
|
|
self.calls.append(("instantiate", template_type, name, params, context))
|
|
return {"instantiated": f"{template_type.value}:{name}"}
|
|
|
|
|
|
class MockInstantiationContext(InstantiationContext):
|
|
"""Mock instantiation context for testing."""
|
|
|
|
def __init__(self, resolves_successfully=True, raise_exception=False):
|
|
super().__init__()
|
|
self.resolves_successfully = resolves_successfully
|
|
self.raise_exception = raise_exception
|
|
self.resolution_calls = []
|
|
|
|
def resolve_reference(self, ref: ComponentReference) -> Any:
|
|
self.resolution_calls.append(ref)
|
|
|
|
if self.raise_exception:
|
|
raise Exception("Mock resolution exception")
|
|
|
|
if self.resolves_successfully:
|
|
return {"resolved": f"{ref.ref_type}:{ref.ref_name}"}
|
|
else:
|
|
return None
|
|
|
|
|
|
@given("I have a clean test environment for stream templates")
|
|
def step_clean_environment_stream_templates(context):
|
|
"""Set up clean test environment for stream templates."""
|
|
context.stream_template = None
|
|
context.template_registry = None
|
|
context.instantiation_context = None
|
|
context.template_params = {}
|
|
context.operators = []
|
|
context.result = None
|
|
context.error = None
|
|
context.processed_operators = None
|
|
|
|
|
|
@given("I have a stream template with basic definition")
|
|
def step_stream_template_basic_definition(context):
|
|
"""Create stream template with basic definition."""
|
|
definition = {
|
|
"type": "stream",
|
|
"stream_type": "cold",
|
|
"operators": [
|
|
{"type": "map", "params": {"function": "transform"}},
|
|
{"type": "filter", "params": {"condition": "valid"}},
|
|
],
|
|
"publications": ["output_stream"],
|
|
}
|
|
context.stream_template = StreamTemplate(
|
|
name="test_stream", template_type=TemplateType.STREAM, definition=definition
|
|
)
|
|
|
|
|
|
@given("I have a stream template with parameters in definition")
|
|
def step_stream_template_with_parameters(context):
|
|
"""Create stream template with parameters section."""
|
|
definition = {
|
|
"parameters": {
|
|
"agent_name": {"type": "string", "required": True},
|
|
"filter_condition": {"type": "string", "default": "default_condition"},
|
|
},
|
|
"type": "stream",
|
|
"stream_type": "cold",
|
|
"operators": [{"type": "map", "params": {"agent": "{{ agent_name }}"}}],
|
|
}
|
|
context.stream_template = StreamTemplate(
|
|
name="parameterized_stream",
|
|
template_type=TemplateType.STREAM,
|
|
definition=definition,
|
|
)
|
|
|
|
|
|
@given("I have a stream template with operators in definition")
|
|
def step_stream_template_with_operators(context):
|
|
"""Create stream template with operators."""
|
|
definition = {
|
|
"type": "stream",
|
|
"operators": [
|
|
{"type": "map", "params": {"agent": "test_agent"}},
|
|
{"type": "filter", "params": {"condition": "test"}},
|
|
],
|
|
}
|
|
context.stream_template = StreamTemplate(
|
|
name="operators_stream",
|
|
template_type=TemplateType.STREAM,
|
|
definition=definition,
|
|
)
|
|
|
|
|
|
@given("I have a stream template without name in definition")
|
|
def step_stream_template_without_name(context):
|
|
"""Create stream template without name in definition."""
|
|
definition = {
|
|
"type": "stream",
|
|
"stream_type": "hot",
|
|
"operators": [{"type": "buffer", "params": {"count": 5}}],
|
|
}
|
|
context.stream_template = StreamTemplate(
|
|
name="unnamed_stream", template_type=TemplateType.STREAM, definition=definition
|
|
)
|
|
|
|
|
|
@given("I have a stream template with name in definition")
|
|
def step_stream_template_with_name(context):
|
|
"""Create stream template with name in definition."""
|
|
definition = {
|
|
"name": "predefined_name",
|
|
"type": "stream",
|
|
"stream_type": "cold",
|
|
"operators": [{"type": "debounce", "params": {"duration": 1.0}}],
|
|
}
|
|
context.stream_template = StreamTemplate(
|
|
name="named_stream", template_type=TemplateType.STREAM, definition=definition
|
|
)
|
|
|
|
|
|
@given("I have valid template parameters")
|
|
def step_valid_template_parameters(context):
|
|
"""Create valid template parameters."""
|
|
context.template_params = {
|
|
"agent_name": "test_agent",
|
|
"filter_condition": "active",
|
|
"timeout": 30,
|
|
"buffer_size": 10,
|
|
}
|
|
|
|
|
|
@given("I have template parameters requiring validation")
|
|
def step_template_parameters_requiring_validation(context):
|
|
"""Create parameters that require validation."""
|
|
context.template_params = {
|
|
"agent_name": "validated_agent",
|
|
"required_param": "required_value",
|
|
"optional_param": None, # Should use default
|
|
}
|
|
|
|
|
|
@given("I have a template registry for stream templates")
|
|
def step_template_registry_stream_templates(context):
|
|
"""Create mock template registry for stream templates."""
|
|
context.template_registry = MockTemplateRegistry()
|
|
|
|
|
|
@given("I have an instantiation context")
|
|
def step_instantiation_context(context):
|
|
"""Create mock instantiation context."""
|
|
context.instantiation_context = MockInstantiationContext()
|
|
|
|
|
|
@given("I have an instantiation context with resolvable agent reference")
|
|
def step_instantiation_context_resolvable_agent(context):
|
|
"""Create context that can resolve agent references."""
|
|
context.instantiation_context = MockInstantiationContext(resolves_successfully=True)
|
|
|
|
|
|
@given("I have an instantiation context with unresolvable agent reference")
|
|
def step_instantiation_context_unresolvable_agent(context):
|
|
"""Create context that cannot resolve agent references."""
|
|
context.instantiation_context = MockInstantiationContext(
|
|
resolves_successfully=False
|
|
)
|
|
|
|
|
|
@given("I have an instantiation context with resolvable graph reference")
|
|
def step_instantiation_context_resolvable_graph(context):
|
|
"""Create context that can resolve graph references."""
|
|
context.instantiation_context = MockInstantiationContext(resolves_successfully=True)
|
|
|
|
|
|
@given("I have an instantiation context with unresolvable graph reference")
|
|
def step_instantiation_context_unresolvable_graph(context):
|
|
"""Create context that cannot resolve graph references."""
|
|
context.instantiation_context = MockInstantiationContext(
|
|
resolves_successfully=False
|
|
)
|
|
|
|
|
|
@given("I have an instantiation context with mixed references")
|
|
def step_instantiation_context_mixed_references(context):
|
|
"""Create context with mixed reference resolution."""
|
|
context.instantiation_context = MockInstantiationContext(resolves_successfully=True)
|
|
|
|
|
|
@given("I have an instantiation context with resolvable references")
|
|
def step_instantiation_context_resolvable_references(context):
|
|
"""Create context with resolvable references."""
|
|
context.instantiation_context = MockInstantiationContext(resolves_successfully=True)
|
|
|
|
|
|
@given("I have an instantiation context that throws exception during resolution")
|
|
def step_instantiation_context_exception(context):
|
|
"""Create context that throws exception during resolution."""
|
|
context.instantiation_context = MockInstantiationContext(
|
|
resolves_successfully=False, raise_exception=True
|
|
)
|
|
|
|
|
|
@given("I have a stream template instance")
|
|
def step_stream_template_instance(context):
|
|
"""Create basic stream template instance."""
|
|
definition = {"type": "stream", "operators": []}
|
|
context.stream_template = StreamTemplate(
|
|
name="test_stream", template_type=TemplateType.STREAM, definition=definition
|
|
)
|
|
|
|
|
|
@given("I have operators list with None operator")
|
|
def step_operators_with_none(context):
|
|
"""Create operators list containing None."""
|
|
context.operators = [
|
|
{"type": "map", "params": {"agent": "test_agent"}},
|
|
None, # Conditionally excluded operator
|
|
{"type": "filter", "params": {"condition": "active"}},
|
|
]
|
|
|
|
|
|
@given("I have operators list with parameterized type")
|
|
def step_operators_parameterized_type(context):
|
|
"""Create operators with parameterized type."""
|
|
context.operators = [
|
|
{"type": "operator_type_param", "params": {"value": "test"}},
|
|
{"type": "map", "params": {"agent": "test_agent"}},
|
|
]
|
|
|
|
|
|
@given("I have template parameters with operator type")
|
|
def step_template_params_operator_type(context):
|
|
"""Create parameters with operator type."""
|
|
context.template_params = {
|
|
"operator_type_param": "debounce",
|
|
"agent_name": "test_agent",
|
|
}
|
|
|
|
|
|
@given("I have operators list with processor graph_execute reference")
|
|
def step_operators_processor_graph_execute(context):
|
|
"""Create operators with processor graph_execute reference."""
|
|
context.operators = [
|
|
{
|
|
"type": "process",
|
|
"params": {
|
|
"processor": {
|
|
"type": "graph_execute",
|
|
"params": {"graph": "test_graph", "input_key": "data"},
|
|
}
|
|
},
|
|
}
|
|
]
|
|
|
|
|
|
@given("I have operators list with processor agent reference")
|
|
def step_operators_processor_agent(context):
|
|
"""Create operators with processor agent reference."""
|
|
context.operators = [
|
|
{
|
|
"type": "process",
|
|
"params": {
|
|
"processor": {
|
|
"type": "agent",
|
|
"params": {"name": "test_agent"},
|
|
}
|
|
},
|
|
}
|
|
]
|
|
|
|
|
|
@given("I have operators list with map operator having agent parameter reference")
|
|
def step_operators_map_agent_param_ref(context):
|
|
"""Create map operator with agent parameter reference."""
|
|
context.operators = [
|
|
{"type": "map", "params": {"agent": "agent_param"}},
|
|
]
|
|
|
|
|
|
@given("I have template parameters with agent name")
|
|
def step_template_params_agent_name(context):
|
|
"""Create parameters with agent name."""
|
|
context.template_params = {
|
|
"agent_param": "resolved_agent",
|
|
"other_param": "other_value",
|
|
}
|
|
|
|
|
|
@given("I have operators list with map operator having agent component reference")
|
|
def step_operators_map_agent_component_ref(context):
|
|
"""Create map operator with agent component reference."""
|
|
context.operators = [
|
|
{"type": "map", "params": {"agent": "component_agent_ref"}},
|
|
]
|
|
|
|
|
|
@given(
|
|
"I have operators list with graph_execute operator having graph parameter reference"
|
|
)
|
|
def step_operators_graph_execute_graph_param_ref(context):
|
|
"""Create graph_execute operator with graph parameter reference."""
|
|
context.operators = [
|
|
{"type": "graph_execute", "params": {"graph": "graph_param"}},
|
|
]
|
|
|
|
|
|
@given("I have template parameters with graph name")
|
|
def step_template_params_graph_name(context):
|
|
"""Create parameters with graph name."""
|
|
context.template_params = {
|
|
"graph_param": "resolved_graph",
|
|
"other_param": "other_value",
|
|
}
|
|
|
|
|
|
@given(
|
|
"I have operators list with graph_execute operator having graph component reference"
|
|
)
|
|
def step_operators_graph_execute_graph_component_ref(context):
|
|
"""Create graph_execute operator with graph component reference."""
|
|
context.operators = [
|
|
{"type": "graph_execute", "params": {"graph": "component_graph_ref"}},
|
|
]
|
|
|
|
|
|
@given("I have operators list with agent component reference")
|
|
def step_operators_with_agent_component_reference(context):
|
|
"""Create operators list with agent component reference."""
|
|
context.operators = [
|
|
{"type": "map", "params": {"agent": "component_agent_ref"}},
|
|
]
|
|
|
|
|
|
@given("I have operators list with mixed operator types")
|
|
def step_operators_mixed_types(context):
|
|
"""Create operators with mixed types."""
|
|
context.operators = [
|
|
{"type": "map", "params": {"agent": "agent_param"}}, # Parameter reference
|
|
{
|
|
"type": "graph_execute",
|
|
"params": {"graph": "component_graph_ref"},
|
|
}, # Component ref
|
|
{
|
|
"type": "process",
|
|
"params": {
|
|
"processor": {"type": "agent", "params": {"name": "proc_agent"}}
|
|
},
|
|
}, # Processor agent
|
|
None, # Conditionally excluded
|
|
{"type": "filter", "params": {"condition": "active"}}, # Regular operator
|
|
]
|
|
|
|
|
|
@given("I have comprehensive template parameters")
|
|
def step_comprehensive_template_params(context):
|
|
"""Create comprehensive template parameters."""
|
|
context.template_params = {
|
|
"agent_param": "resolved_agent_from_param",
|
|
"other_param": "other_value",
|
|
"timeout": 30,
|
|
}
|
|
|
|
|
|
@given("I have empty operators list")
|
|
def step_empty_operators_list(context):
|
|
"""Create empty operators list."""
|
|
context.operators = []
|
|
|
|
|
|
@given("I have template parameters")
|
|
def step_basic_template_parameters(context):
|
|
"""Create basic template parameters."""
|
|
context.template_params = {
|
|
"param1": "value1",
|
|
"param2": "value2",
|
|
}
|
|
|
|
|
|
@given("I have operators list with resolvable references")
|
|
def step_operators_resolvable_references(context):
|
|
"""Create operators with resolvable references."""
|
|
context.operators = [
|
|
{"type": "map", "params": {"agent": "resolvable_agent"}},
|
|
{"type": "graph_execute", "params": {"graph": "resolvable_graph"}},
|
|
]
|
|
|
|
|
|
@given("I have a stream template with parameter definitions")
|
|
def step_stream_template_with_param_definitions(context):
|
|
"""Create stream template with parameter definitions."""
|
|
definition = {
|
|
"parameters": {
|
|
"required_param": {"type": "string", "required": True},
|
|
"optional_param": {"type": "string", "default": "default_value"},
|
|
},
|
|
"type": "stream",
|
|
"operators": [{"type": "map", "params": {"agent": "{{ required_param }}"}}],
|
|
}
|
|
context.stream_template = StreamTemplate(
|
|
name="param_def_stream",
|
|
template_type=TemplateType.STREAM,
|
|
definition=definition,
|
|
)
|
|
|
|
|
|
@given("I have a stream template with mutable definition")
|
|
def step_stream_template_mutable_definition(context):
|
|
"""Create stream template with mutable definition for deep copy testing."""
|
|
definition = {
|
|
"type": "stream",
|
|
"operators": [{"type": "map", "params": {"mutable_list": [1, 2, 3]}}],
|
|
"nested_dict": {"key": {"subkey": "value"}},
|
|
}
|
|
context.stream_template = StreamTemplate(
|
|
name="mutable_stream", template_type=TemplateType.STREAM, definition=definition
|
|
)
|
|
# Store original for comparison
|
|
context.original_definition = copy.deepcopy(definition)
|
|
|
|
|
|
@when("I instantiate the stream template")
|
|
def step_instantiate_stream_template(context):
|
|
"""Instantiate the stream template."""
|
|
try:
|
|
context.result = context.stream_template.instantiate(
|
|
context.template_params,
|
|
context.template_registry,
|
|
context.instantiation_context,
|
|
)
|
|
except Exception as e:
|
|
context.error = e
|
|
|
|
|
|
@when("I process the operators")
|
|
def step_process_operators(context):
|
|
"""Process the operators using _process_operators method."""
|
|
try:
|
|
context.processed_operators = context.stream_template._process_operators(
|
|
context.operators, context.template_params, context.instantiation_context
|
|
)
|
|
except Exception as e:
|
|
context.error = e
|
|
|
|
|
|
@then("the stream definition should be created correctly")
|
|
def step_verify_stream_definition_created(context):
|
|
"""Verify stream definition was created correctly."""
|
|
assert context.error is None, f"Unexpected error: {context.error}"
|
|
assert context.result is not None
|
|
assert isinstance(context.result, dict)
|
|
|
|
|
|
@then("the parameters section should be removed")
|
|
def step_verify_parameters_section_removed(context):
|
|
"""Verify parameters section was removed."""
|
|
assert "parameters" not in context.result
|
|
|
|
|
|
@then("the parameters section should be removed from definition")
|
|
def step_verify_parameters_section_removed_from_definition(context):
|
|
"""Verify parameters section was removed from definition."""
|
|
assert "parameters" not in context.result
|
|
|
|
|
|
@then("template variables should be applied")
|
|
def step_verify_template_variables_applied(context):
|
|
"""Verify template variables were applied."""
|
|
# This verifies that _apply_template_vars was called
|
|
# The actual template variable processing is tested elsewhere
|
|
assert context.result is not None
|
|
|
|
|
|
@then("operators should be processed for references")
|
|
def step_verify_operators_processed(context):
|
|
"""Verify operators were processed for references."""
|
|
if "operators" in context.result:
|
|
assert isinstance(context.result["operators"], list)
|
|
|
|
|
|
@then("the template name should be added to definition")
|
|
def step_verify_template_name_added(context):
|
|
"""Verify template name was added."""
|
|
assert context.result["name"] == context.stream_template.name
|
|
|
|
|
|
@then("the existing name should be preserved")
|
|
def step_verify_existing_name_preserved(context):
|
|
"""Verify existing name was preserved."""
|
|
assert context.result["name"] == "predefined_name"
|
|
|
|
|
|
@then("the None operator should be skipped")
|
|
def step_verify_none_operator_skipped(context):
|
|
"""Verify None operator was skipped."""
|
|
assert context.error is None
|
|
assert context.processed_operators is not None
|
|
assert None not in context.processed_operators
|
|
|
|
|
|
@then("processed operators should not contain None")
|
|
def step_verify_processed_operators_no_none(context):
|
|
"""Verify processed operators don't contain None."""
|
|
assert None not in context.processed_operators
|
|
|
|
|
|
@then("the operator type should be replaced with parameter value")
|
|
def step_verify_operator_type_replaced(context):
|
|
"""Verify operator type was replaced with parameter value."""
|
|
assert context.processed_operators is not None
|
|
# Find the operator that had parameterized type
|
|
found_replaced = False
|
|
for op in context.processed_operators:
|
|
if op.get("type") == "debounce": # This should be the replaced value
|
|
found_replaced = True
|
|
break
|
|
assert found_replaced, "Operator type was not replaced with parameter value"
|
|
|
|
|
|
@then("the operator should be converted to graph_execute type")
|
|
def step_verify_operator_converted_graph_execute(context):
|
|
"""Verify operator was converted to graph_execute type."""
|
|
assert context.processed_operators is not None
|
|
assert len(context.processed_operators) > 0
|
|
op = context.processed_operators[0]
|
|
assert op["type"] == "graph_execute"
|
|
|
|
|
|
@then("the processor params should be applied")
|
|
def step_verify_processor_params_applied(context):
|
|
"""Verify processor params were applied."""
|
|
op = context.processed_operators[0]
|
|
assert "params" in op
|
|
assert "graph" in op["params"]
|
|
assert op["params"]["graph"] == "test_graph"
|
|
|
|
|
|
@then("the operator should be converted to map type")
|
|
def step_verify_operator_converted_map(context):
|
|
"""Verify operator was converted to map type."""
|
|
assert context.processed_operators is not None
|
|
assert len(context.processed_operators) > 0
|
|
op = context.processed_operators[0]
|
|
assert op["type"] == "map"
|
|
|
|
|
|
@then("the agent name should be applied")
|
|
def step_verify_agent_name_applied(context):
|
|
"""Verify agent name was applied."""
|
|
op = context.processed_operators[0]
|
|
assert "params" in op
|
|
assert "agent" in op["params"]
|
|
assert op["params"]["agent"] == "test_agent"
|
|
|
|
|
|
@then("the agent reference should be replaced with parameter value")
|
|
def step_verify_agent_reference_replaced(context):
|
|
"""Verify agent reference was replaced with parameter value."""
|
|
assert context.processed_operators is not None
|
|
op = context.processed_operators[0]
|
|
assert op["params"]["agent"] == "resolved_agent"
|
|
|
|
|
|
@then("the agent reference should be resolved successfully")
|
|
def step_verify_agent_reference_resolved(context):
|
|
"""Verify agent reference was resolved successfully."""
|
|
assert context.processed_operators is not None
|
|
op = context.processed_operators[0]
|
|
assert "agent_config" in op["params"]
|
|
assert op["params"]["agent_config"]["resolved"] == "agent:component_agent_ref"
|
|
|
|
|
|
@then("agent_config should be added to operator params")
|
|
def step_verify_agent_config_added(context):
|
|
"""Verify agent_config was added."""
|
|
op = context.processed_operators[0]
|
|
assert "agent_config" in op["params"]
|
|
|
|
|
|
@then("the agent reference resolution should fail silently")
|
|
def step_verify_agent_reference_resolution_failed(context):
|
|
"""Verify agent reference resolution failed silently."""
|
|
assert context.error is None # Should not raise exception
|
|
assert context.processed_operators is not None
|
|
|
|
|
|
@then("the original agent reference should be preserved")
|
|
def step_verify_original_agent_reference_preserved(context):
|
|
"""Verify original agent reference was preserved."""
|
|
op = context.processed_operators[0]
|
|
assert op["params"]["agent"] == "component_agent_ref" # Original value
|
|
assert "agent_config" not in op["params"] # No resolved config
|
|
|
|
|
|
@then("the graph reference should be replaced with parameter value")
|
|
def step_verify_graph_reference_replaced(context):
|
|
"""Verify graph reference was replaced with parameter value."""
|
|
assert context.processed_operators is not None
|
|
op = context.processed_operators[0]
|
|
assert op["params"]["graph"] == "resolved_graph"
|
|
|
|
|
|
@then("the graph reference should be resolved successfully")
|
|
def step_verify_graph_reference_resolved(context):
|
|
"""Verify graph reference was resolved successfully."""
|
|
assert context.processed_operators is not None
|
|
op = context.processed_operators[0]
|
|
assert "graph_config" in op["params"]
|
|
assert op["params"]["graph_config"]["resolved"] == "graph:component_graph_ref"
|
|
|
|
|
|
@then("graph_config should be added to operator params")
|
|
def step_verify_graph_config_added(context):
|
|
"""Verify graph_config was added."""
|
|
op = context.processed_operators[0]
|
|
assert "graph_config" in op["params"]
|
|
|
|
|
|
@then("the graph reference resolution should fail silently")
|
|
def step_verify_graph_reference_resolution_failed(context):
|
|
"""Verify graph reference resolution failed silently."""
|
|
assert context.error is None # Should not raise exception
|
|
assert context.processed_operators is not None
|
|
|
|
|
|
@then("the original graph reference should be preserved")
|
|
def step_verify_original_graph_reference_preserved(context):
|
|
"""Verify original graph reference was preserved."""
|
|
op = context.processed_operators[0]
|
|
assert op["params"]["graph"] == "component_graph_ref" # Original value
|
|
assert "graph_config" not in op["params"] # No resolved config
|
|
|
|
|
|
@then("all operators should be processed correctly")
|
|
def step_verify_all_operators_processed(context):
|
|
"""Verify all operators were processed correctly."""
|
|
assert context.processed_operators is not None
|
|
# Should process all non-None operators
|
|
expected_count = 4 # map, graph_execute, process, filter (None is skipped)
|
|
assert len(context.processed_operators) == expected_count
|
|
|
|
|
|
@then("references should be resolved appropriately")
|
|
def step_verify_references_resolved_appropriately(context):
|
|
"""Verify references were resolved appropriately."""
|
|
# Check that agent parameter reference was resolved
|
|
map_op = next(op for op in context.processed_operators if op.get("type") == "map")
|
|
assert map_op["params"]["agent"] == "resolved_agent_from_param"
|
|
|
|
|
|
@then("processed operators should be returned")
|
|
def step_verify_processed_operators_returned(context):
|
|
"""Verify processed operators were returned."""
|
|
assert context.processed_operators is not None
|
|
assert isinstance(context.processed_operators, list)
|
|
|
|
|
|
@then("an empty processed operators list should be returned")
|
|
def step_verify_empty_processed_operators_returned(context):
|
|
"""Verify empty processed operators list was returned."""
|
|
assert context.processed_operators is not None
|
|
assert context.processed_operators == []
|
|
|
|
|
|
@then("debug logging should be triggered for successful resolutions")
|
|
def step_verify_debug_logging_triggered(context):
|
|
"""Verify debug logging was triggered."""
|
|
# This tests that logger.debug is called, which happens when references are resolved
|
|
assert len(context.instantiation_context.resolution_calls) > 0
|
|
|
|
|
|
@then("parameters should be validated correctly")
|
|
def step_verify_parameters_validated(context):
|
|
"""Verify parameters were validated correctly."""
|
|
# validate_params was called, which is part of the instantiate method
|
|
assert context.result is not None
|
|
|
|
|
|
@then("the stream definition should use validated parameters")
|
|
def step_verify_stream_uses_validated_params(context):
|
|
"""Verify stream definition uses validated parameters."""
|
|
assert context.result is not None
|
|
|
|
|
|
@then("the original definition should not be modified")
|
|
def step_verify_original_definition_not_modified(context):
|
|
"""Verify original definition was not modified."""
|
|
# Check that the template's definition is still the same as original
|
|
assert context.stream_template.definition == context.original_definition
|
|
|
|
|
|
@then("the returned definition should be a deep copy")
|
|
def step_verify_returned_definition_deep_copy(context):
|
|
"""Verify returned definition is a deep copy."""
|
|
# Modify the returned result and ensure original is unchanged
|
|
if "operators" in context.result:
|
|
original_ops = context.stream_template.definition["operators"]
|
|
context.result["operators"][0]["params"]["mutable_list"].append(999)
|
|
# Original should be unchanged
|
|
assert 999 not in original_ops[0]["params"]["mutable_list"]
|
|
|
|
|
|
@then("the exception should be caught and handled silently")
|
|
def step_verify_exception_caught_silently(context):
|
|
"""Verify exception was caught and handled silently."""
|
|
assert context.error is None # Should not propagate the exception
|
|
assert context.processed_operators is not None
|
|
|
|
|
|
@then("processing should continue for remaining operators")
|
|
def step_verify_processing_continues(context):
|
|
"""Verify processing continued for remaining operators."""
|
|
# Should still process other operators even if one fails
|
|
assert len(context.processed_operators) > 0
|