Files
brent.edwards 4e3bf7d3ad
CI / benchmark-publish (pull_request) Has been skipped
CI / lint (pull_request) Successful in 15s
CI / build (pull_request) Successful in 16s
CI / quality (pull_request) Successful in 18s
CI / security (pull_request) Successful in 34s
CI / typecheck (pull_request) Successful in 35s
CI / unit_tests (pull_request) Successful in 2m26s
CI / integration_tests (pull_request) Successful in 3m12s
CI / docker (pull_request) Successful in 46s
CI / coverage (pull_request) Successful in 4m40s
CI / benchmark-regression (pull_request) Successful in 29m26s
test(cli): add failing tests for agents init --yes missing option
Add TDD-style Behave BDD tests for the missing agents init --yes flag
(bug #522). Five Gherkin scenarios cover: exit code validation, prompt
suppression, -y alias, output summary fields, and interactive-mode
regression guard. Includes Robot Framework smoke tests (tagged @wip)
and ASV benchmarks.

Configure behave.ini to exclude @wip scenarios globally and noxfile.py
to exclude wip-tagged Robot suites, so TDD-failing tests do not break CI.

Review feedback addressed:
- Remove unnecessary # type: ignore from benchmark (outside Pyright scope)
- Fix Then...Then to Then...And in Gherkin (L1)
- Fix CHANGELOG 'three scenarios' to 'five scenarios' (L2)
- Add behave.ini documentation for @wip workaround (Aditya F1)
- Rename Scenario 2 title to 'suppresses interactive prompts' (Aditya F2)

Closes #536
2026-03-06 20:28:37 +00:00

119 lines
4.3 KiB
Python

"""ASV benchmarks for ``agents init --yes`` invocation time.
Measures in-process execution time for the init command with the --yes flag,
which should perform non-interactive initialization using defaults.
These benchmarks target bug #522 and are expected to error until the fix
is applied (the --yes flag does not yet exist).
"""
from __future__ import annotations
import shutil
import sys
import tempfile
from pathlib import Path
from unittest.mock import create_autospec, patch
try:
from cleveragents.cli.main import app
except ModuleNotFoundError:
sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "src"))
from cleveragents.cli.main import app
from typer.testing import CliRunner
from cleveragents.application.services.project_service import ProjectService
class _MockProject:
"""Lightweight stand-in for the Project model with spec fields.
We cannot use ``create_autospec(Project)`` because the spec-required
output fields (``data_dir``, ``config_path``, ``database_status``,
``directories``) do not yet exist on the legacy ``Project`` model.
"""
name: str
path: Path
data_dir: Path
config_path: Path
database_status: str
directories: list[str]
class InitYesFlagSuite:
"""Benchmark ``agents init --yes`` invocation."""
timeout = 30.0
def setup(self) -> None:
self._runner = CliRunner()
self._tmpdir = tempfile.mkdtemp()
self._last_exit_code = -1
def teardown(self) -> None:
shutil.rmtree(self._tmpdir, ignore_errors=True)
def _invoke_with_mock(self, args: list[str], project_name: str) -> None:
"""Invoke the CLI with a mocked container and the given *args*.
Stores the result exit code so benchmark data is only meaningful
when the command succeeds (exit code 0). When ``--yes`` is not yet
implemented the benchmark measures error-path latency; after the
fix it measures real init latency.
"""
with patch(
"cleveragents.application.container.get_container"
) as mock_container:
mock_service = create_autospec(ProjectService, instance=True)
mock_project = _MockProject()
mock_project.name = project_name
mock_project.path = Path(self._tmpdir)
# Pre-populate spec-required fields (specification.md:1381-1386)
# so benchmarks measure real output paths once #522 is fixed.
mock_project.data_dir = Path(self._tmpdir)
mock_project.config_path = Path(self._tmpdir) / "config.toml"
mock_project.database_status = "initialized (schema v3)"
mock_project.directories = ["logs", "cache", "sessions", "contexts"]
mock_service.initialize_project.return_value = mock_project
mock_container.return_value.project_service.return_value = mock_service
result = self._runner.invoke(app, args)
self._last_exit_code = result.exit_code
def time_init_yes_flag(self) -> None:
"""Measure end-to-end latency of ``agents init --yes``."""
self._invoke_with_mock(["init", "--yes"], "bench-project")
def time_init_short_y_flag(self) -> None:
"""Measure end-to-end latency of ``agents init -y``."""
self._invoke_with_mock(["init", "-y"], "bench-project")
def time_init_yes_flag_with_path(self) -> None:
"""Measure latency of ``agents init --yes --path <dir>``.
NOTE: ``--path`` is an implementation detail of the current ``init``
command. The spec (``specification.md:1217``) defines only
``agents init [--yes|-y]`` with no ``--path`` option. When #522
aligns the command with the spec this benchmark may need to be
removed or updated.
"""
self._invoke_with_mock(
["init", "--yes", "--path", self._tmpdir], "bench-path-project"
)
def track_exit_code(self) -> int:
"""Track the CLI exit code as an ASV metric.
Returns 0 when ``--yes`` is correctly implemented; non-zero while
the flag is missing. This lets ASV detect regressions that
reintroduce ``NoSuchOption`` without silently reporting error-path
latency.
"""
self._invoke_with_mock(["init", "--yes"], "bench-project")
return self._last_exit_code
InitYesFlagSuite.track_exit_code.unit = "exit_code"