Files
cleveragents-core/features/steps/acms_context_cli_steps.py
T
HAL9000 40e589eb55
CI / lint (pull_request) Successful in 39s
CI / push-validation (pull_request) Successful in 39s
CI / quality (pull_request) Successful in 55s
CI / helm (pull_request) Successful in 41s
CI / build (pull_request) Successful in 48s
CI / typecheck (pull_request) Successful in 1m13s
CI / security (pull_request) Successful in 1m18s
CI / unit_tests (pull_request) Successful in 4m43s
CI / docker (pull_request) Successful in 1m49s
CI / integration_tests (pull_request) Successful in 10m12s
CI / coverage (pull_request) Successful in 11m2s
CI / status-check (pull_request) Successful in 3s
test(e2e): add edge case scenarios for ACMS context CLI commands
Covers uncovered paths in acms_context.py:
- Empty view name rejection (context show error path)
- Clear without filters warning and auto-confirmation path

This improves code coverage by exercising the following functions:
- acms_context_show empty view validation branch (line 91-93)
- acms_context_clear no-filters warning with confirmation bypass (line 215-219)

Closes #9586
2026-06-03 11:24:21 -04:00

471 lines
16 KiB
Python

"""Step definitions for ACMS context CLI commands."""
from __future__ import annotations
import fnmatch
import io
from typing import Any
from unittest.mock import MagicMock, patch
import typer
from behave import given, then, when
from cleveragents.domain.models.acms.tiers import ContextTier, TieredFragment
from features.mocks.acms_context_mocks import (
make_mock_container,
make_mock_tier_service,
make_tiered_fragment,
)
@given("the ACMS service is initialized")
def step_acms_service_initialized(context: Any) -> None:
"""Initialize the ACMS service for testing."""
context.tier_service = MagicMock()
context.context_data = {}
context.entries_to_remove = []
@given('a test view "{view_name}" exists')
def step_test_view_exists(context: Any, view_name: str) -> None:
"""Create a test view with sample fragments."""
context.test_view = view_name
fragments = [
make_tiered_fragment(
fragment_id=f"frag-{view_name}-1",
resource_id="src/module1.py",
tier=ContextTier.HOT,
token_count=1024,
project_name=view_name,
),
make_tiered_fragment(
fragment_id=f"frag-{view_name}-2",
resource_id="src/module2.py",
tier=ContextTier.WARM,
token_count=2048,
project_name=view_name,
),
]
context.context_data[view_name] = fragments
context.entries_to_remove = fragments
@given('the view "{view_name}" has no context entries')
def step_view_has_no_entries(context: Any, view_name: str) -> None:
"""Set up a view with no context entries."""
context.context_data[view_name] = []
context.entries_to_remove = []
@given('the view "{view_name}" has {count:d} context entries')
def step_view_has_entries(context: Any, view_name: str, count: int) -> None:
"""Set up a view with specified number of context entries."""
tiers = [ContextTier.HOT, ContextTier.WARM, ContextTier.COLD]
fragments = [
make_tiered_fragment(
fragment_id=f"frag-{view_name}-{i}",
resource_id=f"src/module{i}.py",
tier=tiers[i % 3],
token_count=1024 * (i + 1),
project_name=view_name,
tag="deprecated" if i < 2 else "default",
)
for i in range(count)
]
context.context_data[view_name] = fragments
context.entries_to_remove = fragments
@given('{count:d} entries match the path pattern "{pattern}"')
def step_entries_match_path(context: Any, count: int, pattern: str) -> None:
"""Mark entries matching a path pattern."""
context.path_filter = pattern
context.path_match_count = count
@given('{count:d} entries have the tag "{tag}"')
def step_entries_have_tag(context: Any, count: int, tag: str) -> None:
"""Mark entries with a specific tag."""
context.tag_filter = tag
context.tag_match_count = count
@given('{count:d} entries are in tier "{tier}"')
def step_entries_in_tier(context: Any, count: int, tier: str) -> None:
"""Mark entries in a specific tier."""
context.tier_filter = tier
context.tier_match_count = count
@when('I run "agents acms context show {view}"')
def step_run_context_show(context: Any, view: str) -> None:
"""Run the context show command and capture real output."""
from cleveragents.cli.commands.acms_context import acms_context_show
scoped_fragments = context.context_data.get(view, [])
mock_service = make_mock_tier_service(
fragments=scoped_fragments,
scoped_fragments=scoped_fragments,
)
mock_container = make_mock_container(mock_service)
output_buffer = io.StringIO()
mock_console = MagicMock()
captured_lines: list[str] = []
def capture_print(msg: str = "", **kwargs: Any) -> None:
captured_lines.append(str(msg))
output_buffer.write(str(msg) + "\n")
mock_console.print.side_effect = capture_print
with (
patch(
"cleveragents.cli.commands.acms_context.get_container",
return_value=mock_container,
),
patch(
"cleveragents.cli.commands.acms_context._get_console",
return_value=mock_console,
),
):
try:
acms_context_show(view)
context.command_exit_code = 0
except typer.Exit as exc:
context.command_exit_code = (
exc.exit_code if exc.exit_code is not None else 0
)
except SystemExit as exc:
context.command_exit_code = exc.code if exc.code is not None else 0
context.command_output = output_buffer.getvalue()
context.captured_lines = captured_lines
@when('I run "agents acms context clear" and confirm')
def step_run_context_clear_with_confirm(context: Any) -> None:
"""Run the context clear command with confirmation."""
from cleveragents.cli.commands.acms_context import acms_context_clear
entries = context.entries_to_remove
mock_service = make_mock_tier_service(fragments=entries)
mock_container = make_mock_container(mock_service)
output_buffer = io.StringIO()
mock_console = MagicMock()
def capture_print(msg: str = "", **kwargs: Any) -> None:
output_buffer.write(str(msg) + "\n")
mock_console.print.side_effect = capture_print
with (
patch(
"cleveragents.cli.commands.acms_context.get_container",
return_value=mock_container,
),
patch(
"cleveragents.cli.commands.acms_context._get_console",
return_value=mock_console,
),
patch("typer.confirm", return_value=True),
):
try:
acms_context_clear()
context.command_exit_code = 0
except typer.Exit as exc:
context.command_exit_code = (
exc.exit_code if exc.exit_code is not None else 0
)
except SystemExit as exc:
context.command_exit_code = exc.code if exc.code is not None else 0
context.command_output = output_buffer.getvalue()
context.mock_confirm = mock_console
@when('I run "agents acms context clear --yes"')
def step_run_context_clear_yes(context: Any) -> None:
"""Run the context clear command with --yes flag."""
from cleveragents.cli.commands.acms_context import acms_context_clear
entries = context.entries_to_remove
mock_service = make_mock_tier_service(fragments=entries)
mock_container = make_mock_container(mock_service)
output_buffer = io.StringIO()
mock_console = MagicMock()
context.mock_typer_confirm = MagicMock()
def capture_print(msg: str = "", **kwargs: Any) -> None:
output_buffer.write(str(msg) + "\n")
mock_console.print.side_effect = capture_print
with (
patch(
"cleveragents.cli.commands.acms_context.get_container",
return_value=mock_container,
),
patch(
"cleveragents.cli.commands.acms_context._get_console",
return_value=mock_console,
),
patch("typer.confirm", context.mock_typer_confirm),
):
try:
acms_context_clear(yes=True)
context.command_exit_code = 0
except typer.Exit as exc:
context.command_exit_code = (
exc.exit_code if exc.exit_code is not None else 0
)
except SystemExit as exc:
context.command_exit_code = exc.code if exc.code is not None else 0
context.command_output = output_buffer.getvalue()
@when('I run "agents acms context clear --path {pattern} --yes"')
def step_run_context_clear_path(context: Any, pattern: str) -> None:
"""Run the context clear command with path filter."""
from cleveragents.cli.commands.acms_context import acms_context_clear
all_entries: list[TieredFragment] = context.entries_to_remove
filtered = [f for f in all_entries if fnmatch.fnmatch(f.resource_id, pattern)]
mock_service = make_mock_tier_service(fragments=all_entries)
mock_container = make_mock_container(mock_service)
output_buffer = io.StringIO()
mock_console = MagicMock()
def capture_print(msg: str = "", **kwargs: Any) -> None:
output_buffer.write(str(msg) + "\n")
mock_console.print.side_effect = capture_print
with (
patch(
"cleveragents.cli.commands.acms_context.get_container",
return_value=mock_container,
),
patch(
"cleveragents.cli.commands.acms_context._get_console",
return_value=mock_console,
),
):
try:
acms_context_clear(path=pattern, yes=True)
context.command_exit_code = 0
except typer.Exit as exc:
context.command_exit_code = (
exc.exit_code if exc.exit_code is not None else 0
)
except SystemExit as exc:
context.command_exit_code = exc.code if exc.code is not None else 0
context.command_output = output_buffer.getvalue()
context.filtered_count = len(filtered)
@when('I run "agents acms context clear --tag {tag} --yes"')
def step_run_context_clear_tag(context: Any, tag: str) -> None:
"""Run the context clear command with tag filter."""
from cleveragents.cli.commands.acms_context import acms_context_clear
all_entries: list[TieredFragment] = context.entries_to_remove
mock_service = make_mock_tier_service(fragments=all_entries)
mock_container = make_mock_container(mock_service)
output_buffer = io.StringIO()
mock_console = MagicMock()
def capture_print(msg: str = "", **kwargs: Any) -> None:
output_buffer.write(str(msg) + "\n")
mock_console.print.side_effect = capture_print
with (
patch(
"cleveragents.cli.commands.acms_context.get_container",
return_value=mock_container,
),
patch(
"cleveragents.cli.commands.acms_context._get_console",
return_value=mock_console,
),
):
try:
acms_context_clear(tag=tag, yes=True)
context.command_exit_code = 0
except typer.Exit as exc:
context.command_exit_code = (
exc.exit_code if exc.exit_code is not None else 0
)
except SystemExit as exc:
context.command_exit_code = exc.code if exc.code is not None else 0
context.command_output = output_buffer.getvalue()
@when('I run "agents acms context clear --tier {tier} --yes"')
def step_run_context_clear_tier(context: Any, tier: str) -> None:
"""Run the context clear command with tier filter."""
from cleveragents.cli.commands.acms_context import acms_context_clear
all_entries: list[TieredFragment] = context.entries_to_remove
mock_service = make_mock_tier_service(fragments=all_entries)
mock_container = make_mock_container(mock_service)
output_buffer = io.StringIO()
mock_console = MagicMock()
def capture_print(msg: str = "", **kwargs: Any) -> None:
output_buffer.write(str(msg) + "\n")
mock_console.print.side_effect = capture_print
with (
patch(
"cleveragents.cli.commands.acms_context.get_container",
return_value=mock_container,
),
patch(
"cleveragents.cli.commands.acms_context._get_console",
return_value=mock_console,
),
):
try:
acms_context_clear(tier=tier, yes=True)
context.command_exit_code = 0
except typer.Exit as exc:
context.command_exit_code = (
exc.exit_code if exc.exit_code is not None else 0
)
except SystemExit as exc:
context.command_exit_code = exc.code if exc.code is not None else 0
context.command_output = output_buffer.getvalue()
@when('I run "agents acms context show" with help flag')
def step_run_context_show_help(context: Any) -> None:
"""Run the context show help command."""
from cleveragents.cli.commands.acms_context import acms_context_show
context.command_output = (
acms_context_show.__doc__
or "Display the assembled context for a specific ACMS view"
)
context.command_exit_code = 0
@when('I run "agents acms context clear" with help flag')
def step_run_context_clear_help(context: Any) -> None:
"""Run the context clear help command."""
from cleveragents.cli.commands.acms_context import acms_context_clear
context.command_output = (
acms_context_clear.__doc__ or "Remove stale context entries from the ACMS index"
)
context.command_exit_code = 0
@then("no confirmation prompt should be shown")
def step_no_confirmation_prompt(context: Any) -> None:
"""Verify no confirmation prompt was shown (--yes flag bypassed it)."""
mock_confirm = getattr(context, "mock_typer_confirm", None)
if mock_confirm is not None:
mock_confirm.assert_not_called()
@when('I run "agents acms context show" with empty view')
def step_run_context_show_empty_view(context: Any) -> None:
"""Run the context show command with an empty/blank view name."""
from cleveragents.cli.commands.acms_context import acms_context_show
mock_service = make_mock_tier_service()
mock_container = make_mock_container(mock_service)
output_buffer = io.StringIO()
mock_console = MagicMock()
captured_lines: list[str] = []
def capture_print(msg: str = "", **kwargs: Any) -> None:
captured_lines.append(str(msg))
output_buffer.write(str(msg) + "\n")
mock_console.print.side_effect = capture_print
with (
patch(
"cleveragents.cli.commands.acms_context.get_container",
return_value=mock_container,
),
patch(
"cleveragents.cli.commands.acms_context._get_console",
return_value=mock_console,
),
):
try:
acms_context_show("")
context.command_exit_code = 0
except typer.Exit as exc:
context.command_exit_code = (
exc.exit_code if exc.exit_code is not None else 0
)
except SystemExit as exc:
context.command_exit_code = exc.code if exc.code is not None else 0
context.command_output = output_buffer.getvalue()
@when('I run "agents acms context clear" and confirm with yes')
def step_run_context_clear_confirm_yes(context: Any) -> None:
"""Run the context clear command without filters but with auto-confirmation."""
from cleveragents.cli.commands.acms_context import acms_context_clear
entries = context.entries_to_remove
mock_service = make_mock_tier_service(fragments=entries)
mock_container = make_mock_container(mock_service)
output_buffer = io.StringIO()
mock_console = MagicMock()
def capture_print(msg: str = "", **kwargs: Any) -> None:
output_buffer.write(str(msg) + "\n")
mock_console.print.side_effect = capture_print
with (
patch(
"cleveragents.cli.commands.acms_context.get_container",
return_value=mock_container,
),
patch(
"cleveragents.cli.commands.acms_context._get_console",
return_value=mock_console,
),
patch("typer.confirm", return_value=True),
):
try:
acms_context_clear()
context.command_exit_code = 0
except typer.Exit as exc:
context.command_exit_code = (
exc.exit_code if exc.exit_code is not None else 0
)
except SystemExit as exc:
context.command_exit_code = exc.code if exc.code is not None else 0
context.command_output = output_buffer.getvalue()
@then("the exit code should be non-zero")
def step_exit_code_nonzero(context: Any) -> None:
"""Verify the command exited with a non-zero exit code."""
assert context.command_exit_code != 0, (
f"Expected non-zero exit code but got {context.command_exit_code}"
)