Files
agent-framework/python/packages/workflow/tests/test_executor.py
T
Tao Chen c8694a8c76 Python: Define Workflow and Executor APIs (#272)
* Workflow init commit

* Add samples and clean up

* ExecutionContext -> WorkflowContext

* Address comments 1

* Fix mypy

* flatting folder structure, and rename contexts

* Remove add_loop

* Add map reduce sample, remove Activation conditions

* Add AgentExecutor and allow multiple handlers per executor

* Minor improvement

* Add RequestInfoExecutor

* Add unit tests part 1

* Address comments 2

* Pre-commit update

* Add run method and more unit tests

* Add xml docs

* run_stream -> run_streaming

* message_handler -> handler

---------

Co-authored-by: Chris <66376200+crickman@users.noreply.github.com>
Co-authored-by: Evan Mattson <evan.mattson@microsoft.com>
2025-08-06 23:26:15 +00:00

103 lines
4.0 KiB
Python

# Copyright (c) Microsoft. All rights reserved.
import pytest
from agent_framework.workflow import Executor, WorkflowContext, handler
def test_executor_without_handlers():
"""Test that an executor without handlers raises an error when trying to run."""
class MockExecutorWithoutHandlers(Executor):
"""A mock executor that does not implement any handlers."""
pass
with pytest.raises(ValueError):
MockExecutorWithoutHandlers()
def test_executor_handler_without_annotations():
"""Test that an executor with one handler without annotations raises an error when trying to run."""
with pytest.raises(ValueError):
class MockExecutorWithOneHandlerWithoutAnnotations(Executor): # type: ignore
"""A mock executor with one handler that does not implement any annotations."""
@handler
async def handle(self, message, ctx) -> None: # type: ignore
"""A mock handler that does not implement any annotations."""
pass
def test_executor_invalid_handler_signature():
"""Test that an executor with an invalid handler signature raises an error when trying to run."""
with pytest.raises(ValueError):
class MockExecutorWithInvalidHandlerSignature(Executor): # type: ignore
"""A mock executor with an invalid handler signature."""
@handler # type: ignore
async def handle(self, message, other, ctx) -> None: # type: ignore
"""A mock handler with an invalid signature."""
pass
def test_executor_with_valid_handlers():
"""Test that an executor with valid handlers can be instantiated and run."""
class MockExecutorWithValidHandlers(Executor): # type: ignore
"""A mock executor with valid handlers."""
@handler
async def handle_text(self, text: str, ctx: WorkflowContext) -> None: # type: ignore
"""A mock handler with a valid signature."""
pass
@handler
async def handle_number(self, number: int, ctx: WorkflowContext) -> None: # type: ignore
"""Another mock handler with a valid signature."""
pass
executor = MockExecutorWithValidHandlers()
assert executor.id is not None
assert len(executor._handlers) == 2 # type: ignore
assert executor.can_handle("text") is True
assert executor.can_handle(42) is True
assert executor.can_handle(3.14) is False
def test_executor_handlers_with_output_types():
"""Test that an executor with handlers that specify output types can be instantiated and run."""
class MockExecutorWithOutputTypes(Executor): # type: ignore
"""A mock executor with handlers that specify output types."""
@handler(output_types=[str])
async def handle_string(self, text: str, ctx: WorkflowContext) -> None: # type: ignore
"""A mock handler that outputs a string."""
pass
@handler(output_types=[int])
async def handle_integer(self, number: int, ctx: WorkflowContext) -> None: # type: ignore
"""A mock handler that outputs an integer."""
pass
executor = MockExecutorWithOutputTypes()
assert len(executor._handlers) == 2 # type: ignore
string_handler = executor._handlers[str] # type: ignore
assert string_handler is not None
assert string_handler._handler_spec is not None # type: ignore
assert string_handler._handler_spec["name"] == "handle_string" # type: ignore
assert string_handler._handler_spec["message_type"] is str # type: ignore
assert string_handler._handler_spec["output_types"] == [str] # type: ignore
int_handler = executor._handlers[int] # type: ignore
assert int_handler is not None
assert int_handler._handler_spec is not None # type: ignore
assert int_handler._handler_spec["name"] == "handle_integer" # type: ignore
assert int_handler._handler_spec["message_type"] is int # type: ignore
assert int_handler._handler_spec["output_types"] == [int] # type: ignore