fix(concurrency): fix lint and Behave step conflict in thread-safety tests
CI / load-versions (pull_request) Successful in 33s
CI / push-validation (pull_request) Successful in 26s
CI / lint (pull_request) Successful in 57s
CI / typecheck (pull_request) Successful in 1m24s
CI / security (pull_request) Successful in 1m7s
CI / build (pull_request) Successful in 47s
CI / helm (pull_request) Successful in 49s
CI / unit_tests (pull_request) Successful in 6m3s
CI / integration_tests (pull_request) Successful in 8m43s
CI / quality (pull_request) Failing after 11m16s
CI / coverage (pull_request) Has been cancelled
CI / docker (pull_request) Has been cancelled
CI / status-check (pull_request) Has been cancelled
CI / load-versions (pull_request) Successful in 33s
CI / push-validation (pull_request) Successful in 26s
CI / lint (pull_request) Successful in 57s
CI / typecheck (pull_request) Successful in 1m24s
CI / security (pull_request) Successful in 1m7s
CI / build (pull_request) Successful in 47s
CI / helm (pull_request) Successful in 49s
CI / unit_tests (pull_request) Successful in 6m3s
CI / integration_tests (pull_request) Successful in 8m43s
CI / quality (pull_request) Failing after 11m16s
CI / coverage (pull_request) Has been cancelled
CI / docker (pull_request) Has been cancelled
CI / status-check (pull_request) Has been cancelled
- Remove unused imports (Invariant, ULID) from step definitions - Rename ambiguous parameter l -> num_listers (E741) - Fix import ordering in invariant_service.py (RLock before structlog) - Fix line too long in invariant_service.py:208 - Apply ruff format to steps file - Disambiguate @then step text that conflicted with context_tier_thread_safety_steps.py ISSUES CLOSED: #7524
This commit is contained in:
@@ -15,7 +15,7 @@ Feature: InvariantService thread safety (Issue #7524)
|
||||
|
||||
Scenario: InvariantService has a reentrant lock attribute
|
||||
Then the invariant service should have a _lock attribute
|
||||
And the _lock should be a threading.RLock
|
||||
And the invariant service _lock should be a threading.RLock
|
||||
|
||||
# -----------------------------------------------------------------
|
||||
# Concurrent adds
|
||||
|
||||
@@ -13,13 +13,9 @@ import threading
|
||||
from typing import Any
|
||||
|
||||
from behave import given, then, when
|
||||
from ulid import ULID
|
||||
|
||||
from cleveragents.application.services.invariant_service import InvariantService
|
||||
from cleveragents.domain.models.core.invariant import (
|
||||
Invariant,
|
||||
InvariantScope,
|
||||
)
|
||||
from cleveragents.domain.models.core.invariant import InvariantScope
|
||||
|
||||
__all__: list[str] = []
|
||||
|
||||
@@ -58,7 +54,7 @@ def step_then_has_lock(context: Any) -> None:
|
||||
)
|
||||
|
||||
|
||||
@then("the _lock should be a threading.RLock")
|
||||
@then("the invariant service _lock should be a threading.RLock")
|
||||
def step_then_lock_is_rlock(context: Any) -> None:
|
||||
lock = context.invariant_svc._lock
|
||||
assert hasattr(lock, "acquire"), "_lock must have acquire()"
|
||||
@@ -75,9 +71,7 @@ def step_then_lock_is_rlock(context: Any) -> None:
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
@when(
|
||||
"{n:d} threads concurrently add {k:d} invariants each to the invariant service"
|
||||
)
|
||||
@when("{n:d} threads concurrently add {k:d} invariants each to the invariant service")
|
||||
def step_when_concurrent_adds(context: Any, n: int, k: int) -> None:
|
||||
errors: list[Exception] = []
|
||||
lock = threading.Lock()
|
||||
@@ -111,9 +105,7 @@ def step_then_no_runtime_error(context: Any) -> None:
|
||||
)
|
||||
|
||||
|
||||
@then(
|
||||
"the invariant service should contain at least {n:d} active invariants"
|
||||
)
|
||||
@then("the invariant service should contain at least {n:d} active invariants")
|
||||
def step_then_at_least_invariants(context: Any, n: int) -> None:
|
||||
snapshot = context.invariant_svc.get_invariants_snapshot()
|
||||
assert len(snapshot) >= n, (
|
||||
@@ -175,9 +167,9 @@ def step_then_no_exc_list(context: Any) -> None:
|
||||
|
||||
@when(
|
||||
"{a:d} threads concurrently add invariants and "
|
||||
"{l:d} threads concurrently list invariants"
|
||||
"{num_listers:d} threads concurrently list invariants"
|
||||
)
|
||||
def step_when_mixed_access(context: Any, a: int, l: int) -> None:
|
||||
def step_when_mixed_access(context: Any, a: int, num_listers: int) -> None:
|
||||
errors: list[Exception] = []
|
||||
lock = threading.Lock()
|
||||
|
||||
@@ -203,7 +195,9 @@ def step_when_mixed_access(context: Any, a: int, l: int) -> None:
|
||||
errors.append(exc)
|
||||
|
||||
threads = [threading.Thread(target=add_worker, args=(t,)) for t in range(a)]
|
||||
threads += [threading.Thread(target=list_worker, args=(t,)) for t in range(l)]
|
||||
threads += [
|
||||
threading.Thread(target=list_worker, args=(t,)) for t in range(num_listers)
|
||||
]
|
||||
for t in threads:
|
||||
t.start()
|
||||
for t in threads:
|
||||
@@ -224,9 +218,7 @@ def step_then_no_exc_mixed(context: Any) -> None:
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
@given(
|
||||
"{n:d} invariants pre-stored in the invariant service with plan \"{plan_id}\""
|
||||
)
|
||||
@given('{n:d} invariants pre-stored in the invariant service with plan "{plan_id}"')
|
||||
def step_given_pre_stored_with_plan(context: Any, n: int, plan_id: str) -> None:
|
||||
context.pre_stored_ids = []
|
||||
for i in range(n):
|
||||
@@ -239,7 +231,7 @@ def step_given_pre_stored_with_plan(context: Any, n: int, plan_id: str) -> None:
|
||||
|
||||
|
||||
@when(
|
||||
"{n:d} threads concurrently enforce all stored invariants each from plan \"{plan_id}\""
|
||||
'{n:d} threads concurrently enforce all stored invariants each from plan "{plan_id}"'
|
||||
)
|
||||
def step_when_concurrent_enforcement(context: Any, n: int, plan_id: str) -> None:
|
||||
errors: list[Exception] = []
|
||||
@@ -254,8 +246,7 @@ def step_when_concurrent_enforcement(context: Any, n: int, plan_id: str) -> None
|
||||
filtered = [
|
||||
inv
|
||||
for inv in snapshot
|
||||
if inv.scope == InvariantScope.PLAN
|
||||
and inv.source_name == plan_id
|
||||
if inv.scope == InvariantScope.PLAN and inv.source_name == plan_id
|
||||
]
|
||||
if not filtered:
|
||||
continue
|
||||
@@ -284,9 +275,7 @@ def step_then_no_exc_enforce(context: Any) -> None:
|
||||
)
|
||||
|
||||
|
||||
@then(
|
||||
"the invariant service should contain at least {n:d} enforcement records"
|
||||
)
|
||||
@then("the invariant service should contain at least {n:d} enforcement records")
|
||||
def step_then_at_least_records(context: Any, n: int) -> None:
|
||||
records = context.invariant_svc.get_enforcement_records()
|
||||
assert len(records) >= n, (
|
||||
|
||||
@@ -27,10 +27,10 @@ Based on ``docs/specification.md`` and implementation plan Stage M3.5.
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from threading import RLock
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import structlog
|
||||
from threading import RLock
|
||||
from ulid import ULID
|
||||
|
||||
from cleveragents.application.services.prompt_sanitizer import PromptSanitizer
|
||||
@@ -205,7 +205,9 @@ class InvariantService:
|
||||
# Invariant is frozen (immutable); create a new instance with active=False
|
||||
deactivated = inv.model_copy(update={"active": False})
|
||||
self._invariants[invariant_id] = deactivated
|
||||
self._logger.info("Invariant removed (soft-delete)", invariant_id=invariant_id)
|
||||
self._logger.info(
|
||||
"Invariant removed (soft-delete)", invariant_id=invariant_id
|
||||
)
|
||||
return deactivated
|
||||
|
||||
def get_effective_invariants(
|
||||
|
||||
Reference in New Issue
Block a user