From 66ad92f6e988ae19441fbd6db736f5387e0875ee Mon Sep 17 00:00:00 2001 From: "Marco Trinelli (mtrinell)" Date: Thu, 15 May 2025 12:06:04 +0200 Subject: [PATCH] feat: add test for webhook Signed-off-by: Marco Trinelli (mtrinell) --- src/agent_workflow_server/services/runs.py | 2 +- tests/mock.py | 43 ++++++++++++++++++++++ tests/test_runs.py | 23 +++++++++++- 3 files changed, 66 insertions(+), 2 deletions(-) diff --git a/src/agent_workflow_server/services/runs.py b/src/agent_workflow_server/services/runs.py index bf74cd5..ce616b9 100644 --- a/src/agent_workflow_server/services/runs.py +++ b/src/agent_workflow_server/services/runs.py @@ -120,7 +120,7 @@ async def _call_webhook(run: Run) -> None: async with httpx.AsyncClient() as client: response = await client.post( run["webhook"], - data=run_data, + content=run_data, headers={"Content-Type": "application/json"}, ) diff --git a/tests/mock.py b/tests/mock.py index 27f099f..5dbdd62 100644 --- a/tests/mock.py +++ b/tests/mock.py @@ -5,6 +5,8 @@ import json from typing import AsyncGenerator, List, Optional +from aiohttp import web + from agent_workflow_server.agents.base import BaseAdapter, BaseAgent from agent_workflow_server.generated.manifest.models.agent_manifest import AgentManifest from agent_workflow_server.services.message import Message @@ -105,3 +107,44 @@ def load_agent( mock_agent = MockAgentImpl() + + +MOCK_WEBSERVER_DEFAULT_PORT = 9753 +MOCK_WEBSERVER_DEFAULT_HOST = "127.0.0.1" +MOCK_WEBSERVER_WEBHOOK_PATH = "webhook" + + +class TestWebServer: + def __init__(self, host: str, port: int, path: str): + self.host = host + self.port = port + self.path = "/" + path.strip("/") + self.webhook_payload = None + self._runner = None + self._site = None + self._app = web.Application() + self._app.router.add_post(self.path, self._webhook_handler) + self._server_task = None + + async def _webhook_handler(self, request: web.Request) -> web.Response: + self.webhook_payload = await request.read() + return web.Response(status=200) + + async def start(self): + self._runner = web.AppRunner(self._app) + await self._runner.setup() + self._site = web.TCPSite(self._runner, self.host, self.port) + await self._site.start() + + async def stop(self): + if self._site: + await self._site.stop() + if self._runner: + await self._runner.cleanup() + + async def __aenter__(self): + await self.start() + return self + + async def __aexit__(self, exc_type, exc, tb): + await self.stop() diff --git a/tests/test_runs.py b/tests/test_runs.py index ddb5b18..f7e178d 100644 --- a/tests/test_runs.py +++ b/tests/test_runs.py @@ -28,7 +28,11 @@ MOCK_RUN_OUTPUT_ERROR, MOCK_RUN_OUTPUT_INTERRUPT, MOCK_RUN_OUTPUT_STREAM, + MOCK_WEBSERVER_DEFAULT_HOST, + MOCK_WEBSERVER_DEFAULT_PORT, + MOCK_WEBSERVER_WEBHOOK_PATH, MockAdapter, + TestWebServer, ) @@ -45,7 +49,7 @@ recursion_limit=3, configurable={"mock-key": "mock-value"}, ), - webhook="http://some-host:8000/webhook", + webhook=f"http://{MOCK_WEBSERVER_DEFAULT_HOST}:{MOCK_WEBSERVER_DEFAULT_PORT}/{MOCK_WEBSERVER_WEBHOOK_PATH}", ), "success", MOCK_RUN_OUTPUT, @@ -76,6 +80,14 @@ async def test_invoke( expected_status: RunStatus, expected_output: dict, ): + if run_create_mock.webhook: + mock_server = TestWebServer( + host=MOCK_WEBSERVER_DEFAULT_HOST, + port=MOCK_WEBSERVER_DEFAULT_PORT, + path=MOCK_WEBSERVER_WEBHOOK_PATH, + ) + await mock_server.start() + mocker.patch("agent_workflow_server.agents.load.ADAPTERS", [MockAdapter()]) try: @@ -103,8 +115,17 @@ async def test_invoke( assert run.creation.config == run_create_mock.config assert run.creation.webhook == run_create_mock.webhook assert output == expected_output + + # Check if the webhook was called with the expected payload + if run_create_mock.webhook: + assert mock_server.webhook_payload.decode("utf-8") == run.model_dump_json( + by_alias=True, exclude_unset=True + ) + finally: worker_task.cancel() + if run_create_mock.webhook and mock_server: + await mock_server.stop() try: await worker_task except asyncio.CancelledError: