test(mcp): cover timer shutdown scheduling guards
This commit is contained in:
@@ -88,6 +88,35 @@ def step_shared_callback_flag(context: Context) -> None:
|
||||
context.timer_race_callback_lock = threading.Lock()
|
||||
|
||||
|
||||
@given("an McpClient with active idle and health timers")
|
||||
def step_mcp_client_active_timers(context: Context) -> None:
|
||||
"""Create a client whose timer schedulers would normally install timers."""
|
||||
server_config = MCPServerConfig(
|
||||
name="test-timer-shutdown-guard",
|
||||
transport="stdio",
|
||||
command="echo",
|
||||
)
|
||||
context.timer_race_config = McpClientConfig(
|
||||
server=server_config,
|
||||
lazy_start=False,
|
||||
idle_timeout_seconds=60.0,
|
||||
health_check_interval_seconds=60.0,
|
||||
)
|
||||
context.timer_race_transport = MockMCPTransport(
|
||||
tools=[_mock_tool("test_tool")],
|
||||
)
|
||||
context.timer_race_client = McpClient(
|
||||
config=context.timer_race_config,
|
||||
transport=context.timer_race_transport,
|
||||
)
|
||||
|
||||
|
||||
@given("the timer race client is marked as shutting down")
|
||||
def step_mark_timer_race_client_shutting_down(context: Context) -> None:
|
||||
"""Simulate the shutdown window before timer scheduling is attempted."""
|
||||
context.timer_race_client._shutting_down = True
|
||||
|
||||
|
||||
# ── When ──────────────────────────────────────────────────────────
|
||||
|
||||
|
||||
@@ -213,6 +242,13 @@ def step_wait_for_late_fires(context: Context) -> None:
|
||||
original_sleep(0.3)
|
||||
|
||||
|
||||
@when("I ask the client to schedule idle and health timers")
|
||||
def step_schedule_idle_and_health_timers(context: Context) -> None:
|
||||
"""Invoke both scheduler guards while shutdown is in progress."""
|
||||
context.timer_race_client._schedule_idle_timer()
|
||||
context.timer_race_client._schedule_health_check()
|
||||
|
||||
|
||||
# ── Then ──────────────────────────────────────────────────────────
|
||||
|
||||
|
||||
@@ -237,3 +273,11 @@ def step_idle_callback_not_fired_after_shutdown(context: Context) -> None:
|
||||
"different synchronisation scheme to prevent the race. "
|
||||
f"Errors (if any): {getattr(context, 'timer_race_errors', [])}"
|
||||
)
|
||||
|
||||
|
||||
@then("no idle or health timer should be scheduled")
|
||||
def step_no_idle_or_health_timer_scheduled(context: Context) -> None:
|
||||
"""Assert shutdown guards returned before installing timers."""
|
||||
client = context.timer_race_client
|
||||
assert client._idle_timer is None, "Idle timer was scheduled during shutdown"
|
||||
assert client._health_timer is None, "Health timer was scheduled during shutdown"
|
||||
|
||||
@@ -75,4 +75,10 @@ Feature: TDD Issue #10516 — McpClient timer can fire after cancellation race
|
||||
When I start the client
|
||||
And I trigger the idle timer race by forcing a reschedule during shutdown
|
||||
And I wait long enough for any late timer fires (0.3s)
|
||||
Then the idle timer callback should not have fired after shutdown
|
||||
Then the idle timer callback should not have fired after shutdown
|
||||
|
||||
Scenario: Timer schedulers skip work during shutdown
|
||||
Given an McpClient with active idle and health timers
|
||||
And the timer race client is marked as shutting down
|
||||
When I ask the client to schedule idle and health timers
|
||||
Then no idle or health timer should be scheduled
|
||||
|
||||
Reference in New Issue
Block a user