Files
cleveragents-core/features/tdd_mcp_client_start_race.feature
T
HAL9000 bcf1eb9100
CI / push-validation (pull_request) Successful in 25s
CI / build (pull_request) Successful in 41s
CI / lint (pull_request) Successful in 48s
CI / quality (pull_request) Successful in 47s
CI / helm (pull_request) Successful in 46s
CI / typecheck (pull_request) Successful in 58s
CI / security (pull_request) Successful in 1m33s
CI / unit_tests (pull_request) Successful in 6m44s
CI / integration_tests (pull_request) Successful in 10m30s
CI / docker (pull_request) Successful in 1m45s
CI / coverage (pull_request) Successful in 10m23s
CI / status-check (pull_request) Successful in 4s
fix(test): resolve lint errors and remove tdd_expected_fail after #10438 fix
- Move MockMCPTransport import to module level in counting_mcp_transport.py,
  removing the noqa: PLC0415 suppression that caused RUF100 (unused noqa)
- Remove dead `if TYPE_CHECKING: pass` block and unused TYPE_CHECKING import
- Remove unused `from typing import Any` in race condition step definitions (F401)
- Fix excess blank lines (3 → 2) between imports and first section in step file
- Remove @tdd_expected_fail tag from tdd_mcp_client_start_race.feature; the
  bug is fixed so the scenario now passes, and the file's own comment states
  the tag must be removed when #10438 is resolved

ISSUES CLOSED: #10438
2026-06-10 11:14:45 -04:00

28 lines
1.5 KiB
Gherkin

# This test captures bug #10438 — McpClient.start() race condition.
#
# The @tdd_expected_fail tag inverts the test result: the underlying assertion
# fails (proving the bug exists) but CI reports the scenario as passed.
# When #10438 is fixed, the @tdd_expected_fail tag must be removed.
#
# See: https://git.cleverthis.com/cleveragents/cleveragents-core/issues/10438
@tdd_issue @tdd_issue_10438
Feature: TDD Issue #10438 — McpClient.start() race condition allows concurrent double initialization
McpClient.start() releases the threading.RLock after setting _state to STARTING
but before calling connect() and discover_tools(). If two threads call start()
concurrently, both can pass the _started idempotency check (which is still False)
and both proceed to call connect() and discover_tools() simultaneously.
This test proves the race exists by launching multiple threads that call start()
simultaneously via a threading.Barrier and verifying that connect() is called
exactly once (the correct, thread-safe behavior). Without the bug present,
connect() is called exactly once. With the bug, connect() is called multiple times.
Scenario: Concurrent start() calls must invoke connect() exactly once
Given an McpClient with a counting mock transport
When 5 threads call start() concurrently through a barrier
Then connect() should have been called exactly once
And discover_tools() should have been called exactly once
And the client state should be "running"
And all 5 threads should have completed without hanging