test: add TDD bug-capture test for #992 — DI container audit cache failure
CI / lint (pull_request) Failing after 5s
CI / typecheck (pull_request) Failing after 5s
CI / coverage (pull_request) Has been skipped
CI / security (pull_request) Failing after 5s
CI / quality (pull_request) Failing after 2s
CI / unit_tests (pull_request) Failing after 2s
CI / docker (pull_request) Has been skipped
CI / integration_tests (pull_request) Failing after 2s
CI / e2e_tests (pull_request) Failing after 2s
CI / build (pull_request) Failing after 4s
CI / helm (pull_request) Failing after 4s
CI / status-check (pull_request) Failing after 1s
CI / benchmark-publish (pull_request) Has been skipped
CI / benchmark-regression (pull_request) Has been skipped

Add a dedicated Behave bug-capture scenario that reproduces the get_container() audit subscriber initialization caching defect from #992. The steps patch container construction so audit subscriber initialization fails once then succeeds, call get_container() twice, and assert a retry should occur on the second access.

The assertion intentionally fails against current behavior (only one initialization attempt), and the @tdd_expected_fail + @tdd_bug + @tdd_bug_992 tags invert that failure to a CI pass until the production fix lands. This creates a precise regression guard that will only pass without inversion when retry semantics are implemented.

ISSUES CLOSED: #1096
This commit is contained in:
2026-03-26 10:03:40 +00:00
parent d344989387
commit c55ee7e68d
2 changed files with 91 additions and 0 deletions
@@ -0,0 +1,70 @@
"""Step definitions for tdd_di_audit_cache_failure.feature.
This test captures bug #992: ``get_container()`` caches a container even when
eager audit subscriber initialization fails once during startup, and it does
not retry on subsequent ``get_container()`` calls.
The scenario is tagged ``@tdd_expected_fail`` so the expected assertion failure
(which proves the bug still exists) is inverted to a CI pass until the fix for
#992 lands. After the fix, remove ``@tdd_expected_fail``.
"""
from __future__ import annotations
from typing import Any
from behave import given, then, when
from behave.runner import Context
@given("g992- a container whose audit subscriber init fails once then succeeds")
def step_given_container_with_transient_audit_init_failure(context: Context) -> None:
"""Patch container factory so audit subscriber fails once, then succeeds."""
from cleveragents.application import container as container_module
class FakeContainer:
"""Minimal fake container to track audit subscriber initialization calls."""
def __init__(self) -> None:
self.audit_init_attempts = 0
def audit_event_subscriber(self) -> object:
"""Fail first call (simulating DB not ready), then succeed."""
self.audit_init_attempts += 1
if self.audit_init_attempts == 1:
raise RuntimeError("database not ready yet")
return object()
context.g992_original_container_class = container_module.Container
container_module.Container = FakeContainer
def _cleanup() -> None:
container_module.Container = context.g992_original_container_class
container_module.reset_container()
context.add_cleanup(_cleanup)
container_module.reset_container()
@when("g992- I call get_container twice")
def step_when_call_get_container_twice(context: Context) -> None:
"""Call get_container twice and keep references for assertions."""
from cleveragents.application.container import get_container
context.g992_first_container = get_container()
context.g992_second_container = get_container()
@then("g992- audit subscriber init should have been attempted twice")
def step_then_audit_subscriber_should_be_retried(context: Context) -> None:
"""Expect retry on second access after first initialization failure."""
first = context.g992_first_container
second = context.g992_second_container
assert first is second, "Expected get_container() to return a singleton instance"
attempts: Any = getattr(first, "audit_init_attempts", None)
assert attempts == 2, (
"Bug #992: get_container() did not retry audit subscriber initialization "
"after the first failure. Expected 2 attempts after two get_container() "
f"calls, but observed {attempts}."
)
@@ -0,0 +1,21 @@
@tdd_expected_fail @tdd_issue @tdd_issue_992
Feature: TDD Bug #992 — get_container() caches failed audit subscriber initialization
As a long-lived process using the shared DI container
I want get_container() to retry audit subscriber initialization after an initial failure
So that audit subscriptions are eventually registered once prerequisites become available
This feature captures bug #992. Today, get_container() eagerly calls
audit_event_subscriber() only during first container creation. If that first call
fails, the exception is logged and swallowed, but the global _container remains set.
Subsequent get_container() calls return the cached container without retrying the
subscriber initialization.
This scenario is intentionally tagged with @tdd_expected_fail until bug #992 is
fixed. The underlying assertion fails (proving the bug exists) and the tag inversion
mechanism converts that failure to a CI pass. Remove @tdd_expected_fail when #992 is
fixed so this runs as a normal regression test.
Scenario: Bug #992 — get_container retries audit subscriber initialization after first failure
Given g992- a container whose audit subscriber init fails once then succeeds
When g992- I call get_container twice
Then g992- audit subscriber init should have been attempted twice