6ce3385217
CI / lint (push) Successful in 1m29s
CI / typecheck (push) Successful in 1m19s
CI / quality (push) Successful in 1m5s
CI / build (push) Successful in 47s
CI / security (push) Successful in 1m35s
CI / helm (push) Successful in 45s
CI / push-validation (push) Successful in 26s
CI / benchmark-regression (push) Has been skipped
CI / integration_tests (push) Successful in 4m15s
CI / unit_tests (push) Successful in 9m58s
CI / docker (push) Successful in 1m33s
CI / e2e_tests (push) Failing after 15m15s
CI / coverage (push) Successful in 12m27s
CI / status-check (push) Failing after 3s
CI / benchmark-publish (push) Successful in 1h30m14s
CI / benchmark-publish (pull_request) Has been skipped
CI / benchmark-regression (pull_request) Failing after 47s
CI / coverage (pull_request) Successful in 14m32s
CI / lint (pull_request) Successful in 1m8s
CI / quality (pull_request) Successful in 1m28s
CI / security (pull_request) Successful in 1m49s
CI / build (pull_request) Successful in 28s
CI / typecheck (pull_request) Successful in 2m24s
CI / helm (pull_request) Successful in 46s
CI / push-validation (pull_request) Successful in 22s
CI / unit_tests (pull_request) Successful in 6m26s
CI / integration_tests (pull_request) Successful in 4m40s
CI / e2e_tests (pull_request) Successful in 4m47s
CI / docker (pull_request) Successful in 1m31s
CI / status-check (pull_request) Successful in 4s
Adds a Behave TDD issue-capture test for bug #10438: McpClient.start() releases the threading.RLock after setting _state to STARTING but before calling connect() and discover_tools(). Concurrent callers can both pass the _started idempotency check and call discover_tools() multiple times. The test uses @tdd_expected_fail so CI passes while the bug is unfixed. A counting mock transport records connect() and discover_tools() calls. Five threads call start() concurrently through a threading.Barrier to maximise the chance of the race manifesting. ISSUES CLOSED: #10402
28 lines
1.5 KiB
Gherkin
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_expected_fail @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
|