diff --git a/src/automation/__pycache__/__init__.cpython-312.pyc b/src/automation/__pycache__/__init__.cpython-312.pyc index 9015d49..13cc071 100644 Binary files a/src/automation/__pycache__/__init__.cpython-312.pyc and b/src/automation/__pycache__/__init__.cpython-312.pyc differ diff --git a/src/automation/__pycache__/components.cpython-312.pyc b/src/automation/__pycache__/components.cpython-312.pyc index f489f90..9ee5369 100644 Binary files a/src/automation/__pycache__/components.cpython-312.pyc and b/src/automation/__pycache__/components.cpython-312.pyc differ diff --git a/src/automation/__pycache__/engine.cpython-312.pyc b/src/automation/__pycache__/engine.cpython-312.pyc index 8def6af..6a0fea3 100644 Binary files a/src/automation/__pycache__/engine.cpython-312.pyc and b/src/automation/__pycache__/engine.cpython-312.pyc differ diff --git a/src/automation/__pycache__/variables.cpython-312.pyc b/src/automation/__pycache__/variables.cpython-312.pyc index 2e29932..e230748 100644 Binary files a/src/automation/__pycache__/variables.cpython-312.pyc and b/src/automation/__pycache__/variables.cpython-312.pyc differ diff --git a/tests/test_automation_review_regressions.py b/tests/test_automation_review_regressions.py new file mode 100644 index 0000000..844291f --- /dev/null +++ b/tests/test_automation_review_regressions.py @@ -0,0 +1,83 @@ +from automation import __doc__ as automation_doc +from automation.components import Component, ComponentInput, ComponentRegistry, FunctionComponent +from automation.engine import AutomationDefinition, AutomationEngine, RunStatus +from automation.variables import GeneratorVariable + + +def test_collect_includes_peeked_value(): + variable = GeneratorVariable.from_iterable([1, 2, 3]) + + assert variable.peek() == 1 + assert variable.collect() == [1, 2, 3] + + +class LifecycleHelperComponent(Component): + def __init__(self, events, label): + self._events = events + self._label = label + + def setup(self) -> None: + self._events.append(f"{self._label}-setup") + + def teardown(self) -> None: + self._events.append(f"{self._label}-teardown") + + def execute(self, input_: ComponentInput): + return self._ok(input_.payload) + + +def test_register_replaces_component_with_teardown(): + events = [] + registry = ComponentRegistry() + + registry.register("step", LifecycleHelperComponent(events, "old")) + registry.register("step", LifecycleHelperComponent(events, "new")) + assert registry.deregister("step") is True + + assert events == ["old-setup", "old-teardown", "new-setup", "new-teardown"] + + +def test_function_component_returns_traceback_on_failure(): + def broken(input_): + assert input_.name == "broken" + raise RuntimeError("boom") + + output = FunctionComponent(broken, name="broken").execute( + ComponentInput(name="broken", payload=None) + ) + + assert output.success is False + assert output.error is not None + assert "Traceback" in output.error + assert "RuntimeError: boom" in output.error + + +def test_missing_variables_fail_run_instead_of_being_silently_dropped(): + engine = AutomationEngine() + engine.register_fn("echo", lambda input_: input_.payload) + engine.define( + AutomationDefinition( + name="uses-missing-variable", + triggers=["demo"], + steps=["echo"], + variables=["missing"], + ) + ) + + results = engine.trigger_type("demo", payload="hello") + + assert len(results) == 1 + result = results[0] + assert result.status is RunStatus.FAILED + assert result.error is not None + assert "KeyError" in result.error + assert "Variable 'missing' not found in registry" in result.error + assert result.outputs[0].component == "__engine__" + assert result.outputs[0].success is False + + +def test_quick_start_uses_package_imports(): + assert isinstance(automation_doc, str) + assert automation_doc.strip() + assert "from automation import AutomationEngine" in automation_doc + assert "from src.automation import" not in automation_doc