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
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
119 lines
4.3 KiB
Python
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"
|