fix(v3.7.0): resolve issue #1422 #1495

Open
freemo wants to merge 2 commits from fix/1422-docs into master
3 changed files with 252 additions and 4 deletions
@@ -0,0 +1,134 @@
"""Step definitions for validation add output format feature (issue #1422).
Tests that ``agents validation add`` rich output includes:
- Config: field (path to config file)
- Created: field (timestamp)
- Capability panel (Read-Only, Checkpointable, Timeout)
- OK Validation registered footer message
"""
from __future__ import annotations
import os
import tempfile
from typing import Any
from unittest.mock import MagicMock, patch
from behave import given, then, when
from behave.runner import Context
from typer.testing import CliRunner
from cleveragents.cli.commands.validation import app as validation_app
_VALIDATION_YAML = """\
name: local/run-tests
description: Run unit tests with coverage
source: custom
mode: required
code: |
def run(inputs):
return {"passed": True}
"""
_runner = CliRunner()
def _make_mock_validation(
name: str = "local/run-tests",
) -> dict[str, Any]:
"""Create a mock validation dict as returned by the service layer."""
return {
"name": name,
"description": "Run unit tests with coverage",
"source": "custom",
"tool_type": "validation",
"mode": "required",
"timeout": 300,
}
def _patch_val_svc(context: Context) -> Any:
return patch(
"cleveragents.cli.commands.validation._get_tool_registry_service",
return_value=context.val_output_mock_service,
)
# ---------------------------------------------------------------------------
# Background
# ---------------------------------------------------------------------------
@given("a validation add output format test runner with mocks")
def step_val_output_format_runner(context: Context) -> None:
context.val_output_runner = _runner
context.val_output_result = None
context.val_output_yaml_path = None
context.val_output_mock_service = MagicMock()
context.val_output_mock_service.register_tool.return_value = _make_mock_validation()
context.val_output_mock_service.update_tool.return_value = _make_mock_validation()
context.val_output_mock_service.get_tool.return_value = None
# ---------------------------------------------------------------------------
# Given steps
# ---------------------------------------------------------------------------
@given("a validation add output format YAML config at a known path")
def step_val_output_yaml_config(context: Context) -> None:
fd, path = tempfile.mkstemp(suffix=".yaml")
with os.fdopen(fd, "w") as fh:
fh.write(_VALIDATION_YAML)
context.val_output_yaml_path = path
@given("the validation add output format validation already exists")
def step_val_output_already_exists(context: Context) -> None:
context.val_output_mock_service.get_tool.return_value = _make_mock_validation()
context.val_output_mock_service.update_tool.return_value = _make_mock_validation()
# ---------------------------------------------------------------------------
# When steps
# ---------------------------------------------------------------------------
@when("I invoke validation add output format with rich output")
def step_val_output_invoke_rich(context: Context) -> None:
with _patch_val_svc(context):
context.val_output_result = _runner.invoke(
validation_app,
["add", "--config", context.val_output_yaml_path],
)
@when("I invoke validation add output format with --update flag")
def step_val_output_invoke_update(context: Context) -> None:
with _patch_val_svc(context):
context.val_output_result = _runner.invoke(
validation_app,
["add", "--config", context.val_output_yaml_path, "--update"],
)
# ---------------------------------------------------------------------------
# Then assertions
# ---------------------------------------------------------------------------
@then("the validation add output format result should succeed")
def step_val_output_result_success(context: Context) -> None:
assert context.val_output_result is not None
assert context.val_output_result.exit_code == 0, (
f"Expected exit 0, got {context.val_output_result.exit_code}. "
f"Output: {context.val_output_result.output}"
)
@then('the validation add output format output should contain "{text}"')
def step_val_output_contains(context: Context, text: str) -> None:
assert context.val_output_result is not None
assert text in context.val_output_result.output, (
f"Expected '{text}' in output. Got: {context.val_output_result.output}"
)
@@ -0,0 +1,66 @@
@tdd_issue @tdd_issue_1422
Outdated
Review

[BLOCKING] No Robot Framework integration test has been added in robot/ to cover the new agents validation add output format. Per the multi-level testing mandate in CONTRIBUTING.md, all new CLI behavior must be covered at both the unit (Behave) and integration (Robot Framework) levels.

Issue #1422 subtasks explicitly list: Tests (Robot): Update integration test output assertions.

Please add a .robot file in robot/ that invokes agents validation add and asserts the presence of the Capability panel, Config path, Created timestamp, and OK footer message in the command output.


Automated by CleverAgents Bot
Supervisor: PR Review | Agent: pr-review-worker

[BLOCKING] No Robot Framework integration test has been added in `robot/` to cover the new `agents validation add` output format. Per the multi-level testing mandate in CONTRIBUTING.md, all new CLI behavior must be covered at both the unit (Behave) and integration (Robot Framework) levels. Issue #1422 subtasks explicitly list: `Tests (Robot): Update integration test output assertions`. Please add a `.robot` file in `robot/` that invokes `agents validation add` and asserts the presence of the Capability panel, Config path, Created timestamp, and OK footer message in the command output. --- Automated by CleverAgents Bot Supervisor: PR Review | Agent: pr-review-worker
Feature: Bug #1422 — validation add output missing Capability panel, Config path, and Created timestamp
As a user of the CleverAgents CLI
I want the ``agents validation add`` command to display the Config path,
Created timestamp, Capability panel, and footer message in its rich output
So that the output matches the specification at docs/specification.md lines 9319-9360
Background:
Given a validation add output format test runner with mocks
Scenario: validation add rich output includes Config path
Given a validation add output format YAML config at a known path
When I invoke validation add output format with rich output
Then the validation add output format result should succeed
And the validation add output format output should contain "Config:"
Scenario: validation add rich output includes Created timestamp
Given a validation add output format YAML config at a known path
When I invoke validation add output format with rich output
Then the validation add output format result should succeed
And the validation add output format output should contain "Created:"
Scenario: validation add rich output includes Capability panel
Given a validation add output format YAML config at a known path
When I invoke validation add output format with rich output
Then the validation add output format result should succeed
And the validation add output format output should contain "Capability"
Scenario: validation add rich output includes Read-Only enforced field
Given a validation add output format YAML config at a known path
When I invoke validation add output format with rich output
Then the validation add output format result should succeed
And the validation add output format output should contain "Read-Only:"
Scenario: validation add rich output includes Checkpointable enforced field
Given a validation add output format YAML config at a known path
When I invoke validation add output format with rich output
Then the validation add output format result should succeed
And the validation add output format output should contain "Checkpointable:"
Scenario: validation add rich output includes Timeout field
Given a validation add output format YAML config at a known path
When I invoke validation add output format with rich output
Then the validation add output format result should succeed
And the validation add output format output should contain "Timeout:"
Scenario: validation add rich output includes OK footer message
Given a validation add output format YAML config at a known path
When I invoke validation add output format with rich output
Then the validation add output format result should succeed
And the validation add output format output should contain "OK Validation registered"
Scenario: validation add rich output includes Validation Registered panel title
Given a validation add output format YAML config at a known path
When I invoke validation add output format with rich output
Then the validation add output format result should succeed
And the validation add output format output should contain "Validation Registered"
Scenario: validation add with --update flag also shows Config and Capability panel
Given a validation add output format YAML config at a known path
And the validation add output format validation already exists
When I invoke validation add output format with --update flag
Then the validation add output format result should succeed
And the validation add output format output should contain "Config:"
And the validation add output format output should contain "Capability"
And the validation add output format output should contain "OK Validation registered"
+52 -4
View File
2
@@ -48,6 +48,8 @@ Based on implementation_plan.md -- Task C1.tool.cli.
from __future__ import annotations
import sys
from datetime import datetime
from pathlib import Path
from typing import Annotated, Any
1
@@ -68,7 +70,9 @@ from cleveragents.domain.models.core.tool import Validation, ValidationMode
# Create sub-app for validation commands
app = typer.Typer(help="Manage validations (pass/fail tools) and resource attachments.")
console = Console()
# Use stdout so Typer/CliRunner captures output in result.output (BDD tests
# assert on result.output; Rich defaults to stderr which would break those).
console = Console(file=sys.stdout)
# Reusable --format option description
_FORMAT_HELP = "Output format: json, yaml, plain, table, or rich (default: rich)"
@@ -136,8 +140,18 @@ def _print_validation(
tool: Any,
title: str = "Validation",
fmt: str = OutputFormat.RICH.value,
config_path: str | None = None,
created_at: datetime | None = None,
) -> None:
"""Print validation details in the requested format."""
"""Print validation details in the requested format.
Args:
tool: The validation tool object to print
title: Panel title (e.g., "Validation Registered")
fmt: Output format (rich, json, yaml, etc.)
config_path: Path to the config file (optional)
created_at: Timestamp of creation (optional)
"""
data = _validation_spec_dict(tool)
if fmt != OutputFormat.RICH.value:
console.print(format_output(data, fmt))
@@ -155,6 +169,15 @@ def _print_validation(
f"[bold]Mode:[/bold] {mode}"
)
# Add Config field if provided
if config_path:
details += f"\n[bold]Config:[/bold] {config_path}"
# Add Created field if provided
if created_at:
created_str = created_at.strftime("%Y-%m-%d %H:%M")
details += f"\n[bold]Created:[/bold] {created_str}"
wraps = data.get("wraps")
if wraps:
details += f"\n[bold]Wraps:[/bold] {wraps}"
@@ -162,8 +185,21 @@ def _print_validation(
if transform:
details += f"\n[bold]Transform:[/bold] {transform}"
# Print main panel
console.print(Panel(details, title=title, expand=False))
# Add Capability panel
timeout = getattr(tool, "timeout", 300)
capability_details = (
f"[bold]Read-Only:[/bold] true (enforced)\n"
f"[bold]Checkpointable:[/bold] false (enforced)\n"
f"[bold]Timeout:[/bold] {timeout}s"
)
console.print(Panel(capability_details, title="Capability", expand=False))
# Add footer message
console.print("[green]✓ OK Validation registered[/green]")
@app.command("add")
def add(
@@ -239,11 +275,23 @@ def add(
existing = service.get_tool(validation.name)
if existing is not None:
registered = service.update_tool(validation)
_print_validation(registered, title="Validation Updated", fmt=fmt)
_print_validation(
registered,
title="Validation Updated",
fmt=fmt,
config_path=str(config),
created_at=datetime.now(),
)
return
registered = service.register_tool(validation)
_print_validation(registered, title="Validation Registered", fmt=fmt)
_print_validation(
registered,
title="Validation Registered",
fmt=fmt,
config_path=str(config),
created_at=datetime.now(),
)
except FileNotFoundError as exc:
console.print(f"[red]Config file error:[/red] {exc}")