fix(tests): patch _get_session_service directly to eliminate parallel-worker race condition #9213
@@ -713,6 +713,19 @@ def after_scenario(context, scenario):
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
# Reset session CLI module-level service singleton so that no stale
|
||||
# service instance leaks into the next scenario. Without this reset,
|
||||
# a scenario that sets _service to a real container-constructed instance
|
||||
# would leave it cached; a subsequent scenario that patches _service
|
||||
# via unittest.mock.patch would restore to the stale real instance on
|
||||
# cleanup, causing the next scenario to hit the real container and fail.
|
||||
try:
|
||||
from cleveragents.cli.commands.session import _reset_session_service
|
||||
|
||||
_reset_session_service()
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
# Clean up service instances
|
||||
for attr in ["context_service", "plan_service", "project_service"]:
|
||||
if hasattr(context, attr):
|
||||
|
||||
@@ -101,7 +101,20 @@ def _mock_service() -> MagicMock:
|
||||
|
||||
|
||||
def _patch_service(context, svc):
|
||||
patcher = patch("cleveragents.cli.commands.session._service", svc)
|
||||
"""Patch _get_session_service to return *svc* deterministically.
|
||||
|
||||
Patching the function directly (rather than the module-level ``_service``
|
||||
attribute) prevents a race condition in parallel Behave workers: if a
|
||||
concurrent worker's cleanup resets ``_service`` to ``None`` while this
|
||||
scenario's CLI command is executing, ``_get_session_service()`` would fall
|
||||
through to the real DI container and raise, producing a spurious exit
|
||||
code 1. Patching the function itself short-circuits the cache check
|
||||
entirely and is immune to cross-worker ``_service`` mutations.
|
||||
"""
|
||||
patcher = patch(
|
||||
"cleveragents.cli.commands.session._get_session_service",
|
||||
return_value=svc,
|
||||
)
|
||||
patcher.start()
|
||||
context._scvbst_cleanups.append(patcher.stop)
|
||||
|
||||
|
||||
@@ -72,12 +72,24 @@ def _mock_service() -> MagicMock:
|
||||
return svc
|
||||
|
||||
|
||||
# ---- helpers to patch the module-level _service ---------------------------
|
||||
# ---- helpers to patch the module-level service accessor -------------------
|
||||
|
||||
|
||||
def _patch_service(context, svc):
|
||||
"""Patch session._service and register cleanup."""
|
||||
patcher = patch("cleveragents.cli.commands.session._service", svc)
|
||||
"""Patch _get_session_service to return *svc* deterministically.
|
||||
|
||||
Patching the function directly (rather than the module-level ``_service``
|
||||
attribute) prevents a race condition in parallel Behave workers: if a
|
||||
concurrent worker's cleanup resets ``_service`` to ``None`` while this
|
||||
scenario's CLI command is executing, ``_get_session_service()`` would fall
|
||||
through to the real DI container and raise, producing a spurious exit
|
||||
code 1. Patching the function itself short-circuits the cache check
|
||||
entirely and is immune to cross-worker ``_service`` mutations.
|
||||
"""
|
||||
patcher = patch(
|
||||
"cleveragents.cli.commands.session._get_session_service",
|
||||
return_value=svc,
|
||||
)
|
||||
patcher.start()
|
||||
context._cleanup_handlers.append(patcher.stop)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user