# This test captures bug #10438 — McpClient.start() race condition allowing
# concurrent double initialisation.
#
# The fix adds a check for ``_state == McpClientState.STARTING`` inside the
# lock so that a second concurrent caller sees the in-progress state and
# returns immediately, preventing double initialisation.
#
# 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 initialisation
  McpClient.start() previously released the threading.RLock after checking
  ``_started`` but before calling ``connect()`` and ``discover_tools()``.
  Concurrent callers could both pass the idempotency check and initialise
  the MCP server connection multiple times, causing resource leaks and state
  corruption.

  The fix adds ``_state == McpClientState.STARTING`` to the guard inside the
  lock so that a second concurrent caller returns immediately.

  Scenario: Concurrent start() calls result in exactly one connect() invocation
    Given an MCP client configured for concurrent start testing
    When 5 threads call start() simultaneously through a barrier
    Then connect should have been called exactly once
    And discover_tools should have been called exactly once
    And the MCP client state should be running after concurrent starts

  Scenario: Concurrent start() calls leave the client in RUNNING state
    Given an MCP client configured for concurrent start testing
    When 10 threads call start() simultaneously through a barrier
    Then the MCP client state should be running after concurrent starts
    And all concurrent start threads should have completed without error

  Scenario: Sequential start() calls remain idempotent after the fix
    Given an MCP client configured for concurrent start testing
    When I call start() sequentially 3 times
    Then connect should have been called exactly once
    And discover_tools should have been called exactly once
    And the MCP client state should be running after concurrent starts
