# #region Test.AgentChat.ToolTimeout [C:3] [TYPE Module] [SEMANTICS test,agent,tools,timeout] # @BRIEF Contract tests for _execute_with_timeout — configurable timeout wrapper. # @RELATION BINDS_TO -> [AgentChat.Tools.Timeout] # @TEST_EDGE: complete_under_timeout -> Tool completes normally, returns result # @TEST_EDGE: read_tool_timeout -> Read tool exceeds timeout, raises TimeoutError # @TEST_EDGE: write_tool_timeout -> Write tool exceeds timeout, raises TimeoutError import asyncio from unittest.mock import AsyncMock, patch import pytest # ── Tests ─────────────────────────────────────────────────────────── # #region test_completes_under_timeout [C:2] [TYPE Function] # @BRIEF GIVEN a tool that returns quickly WHEN _execute_with_timeout is called with a 30s timeout THEN the result is returned normally. @pytest.mark.asyncio async def test_completes_under_timeout(): """Tool returns its result before the timeout expires.""" from ss_tools.agent.tools import _execute_with_timeout expected = {"status": "ok", "data": [1, 2, 3]} fast_fn = AsyncMock(return_value=expected) with patch("ss_tools.agent.tools.logger.explore") as mock_explore: result = await _execute_with_timeout("fast_tool", fast_fn, is_write=False, timeout_s=30) assert result == expected fast_fn.assert_called_once() mock_explore.assert_not_called() # #endregion test_completes_under_timeout # #region test_read_tool_timeout [C:2] [TYPE Function] # @BRIEF GIVEN a read tool that exceeds the timeout WHEN _execute_with_timeout is called THEN TimeoutError is raised and logger.explore is invoked. @pytest.mark.asyncio async def test_read_tool_timeout(): """Read tool that sleeps longer than timeout_s must raise TimeoutError.""" from ss_tools.agent.tools import _execute_with_timeout async def slow_read(): await asyncio.sleep(0.3) return "never_reached" with patch("ss_tools.agent.tools.logger.explore") as mock_explore: with pytest.raises(TimeoutError): await _execute_with_timeout("slow_read", slow_read, is_write=False, timeout_s=0.05) mock_explore.assert_called_once() call_args = mock_explore.call_args assert call_args[0][0] == "Tool timeout" payload = call_args[1]["payload"] assert payload["tool"] == "slow_read" assert payload["timeout_s"] == 0.05 assert payload["is_write"] is False assert call_args[1]["extra"]["src"] == "AgentChat.Tools.Timeout" # #endregion test_read_tool_timeout # #region test_write_tool_timeout [C:2] [TYPE Function] # @BRIEF GIVEN a write tool that exceeds the timeout WHEN _execute_with_timeout is called THEN TimeoutError is raised with is_write=True logged. @pytest.mark.asyncio async def test_write_tool_timeout(): """Write tool that sleeps longer than timeout_s must raise TimeoutError.""" from ss_tools.agent.tools import _execute_with_timeout async def slow_write(): await asyncio.sleep(0.3) return "never_reached" with patch("ss_tools.agent.tools.logger.explore") as mock_explore: with pytest.raises(TimeoutError): await _execute_with_timeout("slow_write", slow_write, is_write=True, timeout_s=0.05) mock_explore.assert_called_once() call_args = mock_explore.call_args assert call_args[0][0] == "Tool timeout" payload = call_args[1]["payload"] assert payload["tool"] == "slow_write" assert payload["timeout_s"] == 0.05 assert payload["is_write"] is True assert call_args[1]["extra"]["src"] == "AgentChat.Tools.Timeout" # #endregion test_write_tool_timeout # #endregion Test.AgentChat.ToolTimeout