发布

  • test(llm_utils): pin daemon-thread contract for in-loop async close (#4078)

    frostbyte_neo 发布于 2026-05-17 09:50:06 +00:00

    • test(llm_utils): pin daemon-thread contract for in-loop async close

    The existing tests/utilities/test_close_base_llm.py already covers
    the sync + async + in-loop + timeout + idempotence + FD-growth cases
    for _close_base_llm. Two narrow contracts remained unpinned:

    • Daemon flag — the cleanup thread at llm_utils.py:154-159 must
      be daemon=True or a stuck aclose() would hold up Python
      interpreter shutdown. The comment at llm_utils.py:140-143 documents
      this requirement but no test asserted it.

    • In-loop close marks _ldr_closed even when inner aclose
      raises
      — the cleanup thread runs asyncio.run(aclose()) inside
      a try/except Exception (lines 146-152). When aclose raises,
      the thread exits cleanly and the main thread sees
      t.is_alive() == False, then sets _ldr_closed = True (line
      178). The pre-existing test_swallows_async_close_exception
      covered this invariant for the no-loop branch only.

    New class TestInLoopCleanupThreadContract adds two tests:

    • test_cleanup_thread_is_daemon_so_shutdown_is_not_blocked
      patches threading.Thread with a subclass that captures the
      constructor kwargs; verifies daemon=True and a stable name
      prefix ("ldr").
    • test_in_loop_close_marks_closed_even_when_inner_aclose_raises
      — invokes _close_base_llm inside asyncio.run with an
      aclose that raises; asserts _ldr_closed is set anyway.

    Mutation-checked:

    • Flipping daemon=True to daemon=False → the daemon test fails.
    • Removing the async_httpx._ldr_closed = True line from the
      in-loop completion path (llm_utils.py:178) → 3 tests fail: both new
      cases AND the existing test_closes_async_inside_running_loop_via_thread
      / test_in_loop_close_is_idempotent. The fact that the existing
      in-loop idempotence test already covered the happy-path mark is
      reassuring; my new test covers the exception-path mark.

    0 production changes. 24 close-base-llm tests pass (was 22).

    • test(llm_utils): replace line-number refs with symbol-based ones

    AI reviewer flagged that the docstrings on the new tests in PR #4078
    cite specific line numbers in llm_utils.py (e.g.
    llm_utils.py:154-159, :140-143, :173-178) which will
    become stale on any refactor of the target module.

    Replace with stable symbol / branch-name references:

    • llm_utils.py:154-159 (Thread construction site) →
      "the else: # A loop is running in this thread block that
      spawns a ldr-async-llm-close thread"
    • llm_utils.py:140-143 (docstring warning) →
      "the docstring of _close_base_llm ... when motivating the
      brief daemon thread"
    • llm_utils.py:146-152 (try/except around asyncio.run) →
      "the cleanup thread's _close_in_thread runs
      asyncio.run(aclose()) inside a try/except Exception"
    • llm_utils.py:178 (the sentinel-set line) →
      "the else branch that sets _ldr_closed = True"

    No behavior change; both tests still pass and still pin the same
    contracts. Follow-up to a recommendation in the AI Code Reviewer
    comment on PR #4078.

    下载附件