forked from cleveragents/cleveragents-core
aa5d5eeaf5
Implement TDD bug-capture tests for bug #570 where `agents session create` fails because `_get_session_service()` calls `container.db()` which does not exist on the DI Container class (AttributeError). Same root cause as bug #554. Behave BDD scenarios tagged @tdd_bug @tdd_bug_570 @tdd_expected_fail exercise the real DI path (no mocks). Includes Robot Framework integration smoke tests with self-inverting helper and ASV benchmark baseline. ISSUES CLOSED: #631
76 lines
2.7 KiB
Python
76 lines
2.7 KiB
Python
"""Shared step definitions for TDD session DI bug tests.
|
|
|
|
Steps in this module are used by both ``tdd_session_create_di.feature`` and
|
|
``tdd_session_list_di.feature``. Behave loads all step files globally, so
|
|
placing shared steps here avoids duplication and satisfies the CONTRIBUTING.md
|
|
rule that feature-specific steps live in matching ``*_steps.py`` files while
|
|
shared steps live in clearly named reusable modules.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import json
|
|
import os
|
|
import tempfile
|
|
from pathlib import Path
|
|
|
|
from behave import given, then
|
|
from behave.runner import Context
|
|
from typer.testing import CliRunner
|
|
|
|
from cleveragents.application.container import reset_container
|
|
from cleveragents.cli.commands import session as session_mod
|
|
from cleveragents.config.settings import Settings
|
|
|
|
|
|
@given("a CLI runner using the real session DI path")
|
|
def step_real_di_runner(context: Context) -> None:
|
|
"""Set up a CLI runner that does NOT mock the session service.
|
|
|
|
By ensuring ``session_mod._service`` is ``None``, the CLI will call
|
|
``_get_session_service()`` which hits the real DI container and
|
|
triggers the ``container.db()`` bug.
|
|
"""
|
|
context.runner = CliRunner()
|
|
|
|
# Ensure we go through the real DI path — no mock service.
|
|
session_mod._service = None
|
|
|
|
# Provide a database URL so the container can be constructed (the bug
|
|
# triggers before the URL is actually used).
|
|
fd, db_path = tempfile.mkstemp(suffix=".db")
|
|
os.close(fd)
|
|
context._tdd_db_path = db_path
|
|
os.environ["CLEVERAGENTS_DATABASE_URL"] = f"sqlite:///{db_path}"
|
|
|
|
def _cleanup() -> None:
|
|
session_mod._service = None
|
|
os.environ.pop("CLEVERAGENTS_DATABASE_URL", None)
|
|
reset_container()
|
|
# Reset the Settings singleton so stale database URLs from this
|
|
# scenario do not leak into subsequent scenarios.
|
|
Settings._instance = None
|
|
Path(db_path).unlink(missing_ok=True)
|
|
|
|
context.add_cleanup(_cleanup)
|
|
|
|
|
|
@then("the session {subcommand} command should exit successfully")
|
|
def step_session_exits_ok(context: Context, subcommand: str) -> None:
|
|
"""Assert the command exits with code 0."""
|
|
assert context.result.exit_code == 0, (
|
|
f"Expected exit code 0, got {context.result.exit_code}.\n"
|
|
f"Output:\n{context.result.output}"
|
|
)
|
|
|
|
|
|
@then("the session {subcommand} output should be valid JSON")
|
|
def step_session_output_json(context: Context, subcommand: str) -> None:
|
|
"""Assert the output is parseable JSON."""
|
|
try:
|
|
json.loads(context.result.output)
|
|
except json.JSONDecodeError as exc:
|
|
raise AssertionError(
|
|
f"Output is not valid JSON:\n{context.result.output}"
|
|
) from exc
|