200 lines
6.7 KiB
Python
200 lines
6.7 KiB
Python
"""Helper script for invariant_cli.robot smoke tests.
|
|
|
|
Each subcommand is a self-contained check that prints a sentinel on success.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import sys
|
|
from pathlib import Path
|
|
from unittest.mock import patch
|
|
|
|
_SRC = str(Path(__file__).resolve().parents[1] / "src")
|
|
if _SRC not in sys.path:
|
|
sys.path.insert(0, _SRC)
|
|
|
|
from typer.testing import CliRunner # noqa: E402
|
|
|
|
from cleveragents.application.services.invariant_service import ( # noqa: E402
|
|
InvariantService,
|
|
)
|
|
from cleveragents.cli.commands.invariant import app as invariant_app # noqa: E402
|
|
|
|
runner = CliRunner()
|
|
|
|
|
|
def _fresh_service() -> InvariantService:
|
|
"""Create a fresh in-memory service for each test."""
|
|
return InvariantService()
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Subcommands
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
def add_global() -> None:
|
|
svc = _fresh_service()
|
|
with patch("cleveragents.cli.commands.invariant._get_service", return_value=svc):
|
|
result = runner.invoke(
|
|
invariant_app, ["add", "--global", "Never delete production data"]
|
|
)
|
|
if result.exit_code == 0 and "Invariant added" in result.stdout:
|
|
print("invariant-add-global-ok")
|
|
else:
|
|
print(f"FAIL: exit={result.exit_code} out={result.stdout}")
|
|
sys.exit(1)
|
|
|
|
|
|
def add_project() -> None:
|
|
svc = _fresh_service()
|
|
with patch("cleveragents.cli.commands.invariant._get_service", return_value=svc):
|
|
result = runner.invoke(
|
|
invariant_app, ["add", "--project", "myapp", "All API changes need tests"]
|
|
)
|
|
if result.exit_code == 0 and "Invariant added" in result.stdout:
|
|
print("invariant-add-project-ok")
|
|
else:
|
|
print(f"FAIL: exit={result.exit_code} out={result.stdout}")
|
|
sys.exit(1)
|
|
|
|
|
|
def add_plan() -> None:
|
|
svc = _fresh_service()
|
|
with patch("cleveragents.cli.commands.invariant._get_service", return_value=svc):
|
|
result = runner.invoke(
|
|
invariant_app,
|
|
["add", "--plan", "01TESTPLANID00000000000000", "Use Python 3.13"],
|
|
)
|
|
if result.exit_code == 0 and "Invariant added" in result.stdout:
|
|
print("invariant-add-plan-ok")
|
|
else:
|
|
print(f"FAIL: exit={result.exit_code} out={result.stdout}")
|
|
sys.exit(1)
|
|
|
|
|
|
def add_action() -> None:
|
|
svc = _fresh_service()
|
|
with patch("cleveragents.cli.commands.invariant._get_service", return_value=svc):
|
|
result = runner.invoke(
|
|
invariant_app,
|
|
["add", "--action", "local/code-coverage", "Min 80% coverage"],
|
|
)
|
|
if result.exit_code == 0 and "Invariant added" in result.stdout:
|
|
print("invariant-add-action-ok")
|
|
else:
|
|
print(f"FAIL: exit={result.exit_code} out={result.stdout}")
|
|
sys.exit(1)
|
|
|
|
|
|
def list_empty() -> None:
|
|
svc = _fresh_service()
|
|
with patch("cleveragents.cli.commands.invariant._get_service", return_value=svc):
|
|
result = runner.invoke(invariant_app, ["list"])
|
|
if result.exit_code == 0 and "No invariants found" in result.stdout:
|
|
print("invariant-list-empty-ok")
|
|
else:
|
|
print(f"FAIL: exit={result.exit_code} out={result.stdout}")
|
|
sys.exit(1)
|
|
|
|
|
|
def list_filter() -> None:
|
|
svc = _fresh_service()
|
|
svc.add_invariant("Global rule", scope=_scope("global"), source_name="system")
|
|
svc.add_invariant("Project rule", scope=_scope("project"), source_name="myapp")
|
|
with patch("cleveragents.cli.commands.invariant._get_service", return_value=svc):
|
|
result = runner.invoke(invariant_app, ["list", "--global"])
|
|
if result.exit_code == 0 and "Global rule" in result.stdout:
|
|
print("invariant-list-filter-ok")
|
|
else:
|
|
print(f"FAIL: exit={result.exit_code} out={result.stdout}")
|
|
sys.exit(1)
|
|
|
|
|
|
def remove() -> None:
|
|
svc = _fresh_service()
|
|
inv = svc.add_invariant(
|
|
"To be removed", scope=_scope("global"), source_name="system"
|
|
)
|
|
with patch("cleveragents.cli.commands.invariant._get_service", return_value=svc):
|
|
result = runner.invoke(invariant_app, ["remove", "--yes", inv.id])
|
|
if result.exit_code == 0 and "Invariant removed" in result.stdout:
|
|
print("invariant-remove-ok")
|
|
else:
|
|
print(f"FAIL: exit={result.exit_code} out={result.stdout}")
|
|
sys.exit(1)
|
|
|
|
|
|
def scope_conflict() -> None:
|
|
svc = _fresh_service()
|
|
with patch("cleveragents.cli.commands.invariant._get_service", return_value=svc):
|
|
result = runner.invoke(
|
|
invariant_app,
|
|
["add", "--global", "--project", "myapp", "Conflicting scopes"],
|
|
)
|
|
# Should fail with a bad parameter error
|
|
if result.exit_code != 0:
|
|
print("invariant-scope-conflict-ok")
|
|
else:
|
|
print(f"FAIL: exit={result.exit_code} out={result.stdout}")
|
|
sys.exit(1)
|
|
|
|
|
|
def add_no_scope() -> None:
|
|
svc = _fresh_service()
|
|
with patch("cleveragents.cli.commands.invariant._get_service", return_value=svc):
|
|
result = runner.invoke(invariant_app, ["add", "Missing scope invariant"])
|
|
output = result.output or ""
|
|
if result.exit_code == 0 and "Invariant added" in output:
|
|
print("invariant-add-no-scope-global-ok")
|
|
else:
|
|
print(f"FAIL: exit={result.exit_code} out={result.stdout}")
|
|
sys.exit(1)
|
|
|
|
|
|
def list_json() -> None:
|
|
svc = _fresh_service()
|
|
svc.add_invariant("JSON test rule", scope=_scope("global"), source_name="system")
|
|
with patch("cleveragents.cli.commands.invariant._get_service", return_value=svc):
|
|
result = runner.invoke(invariant_app, ["list", "--format", "json"])
|
|
if result.exit_code == 0:
|
|
# Verify output is valid JSON-like
|
|
output = result.stdout.strip()
|
|
if "JSON test rule" in output:
|
|
print("invariant-list-json-ok")
|
|
return
|
|
print(f"FAIL: exit={result.exit_code} out={result.stdout}")
|
|
sys.exit(1)
|
|
|
|
|
|
def _scope(name: str):
|
|
from cleveragents.domain.models.core.invariant import InvariantScope
|
|
|
|
return InvariantScope(name)
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Dispatcher
|
|
# ---------------------------------------------------------------------------
|
|
|
|
COMMANDS = {
|
|
"add-global": add_global,
|
|
"add-project": add_project,
|
|
"add-plan": add_plan,
|
|
"add-action": add_action,
|
|
"list-empty": list_empty,
|
|
"list-filter": list_filter,
|
|
"remove": remove,
|
|
"scope-conflict": scope_conflict,
|
|
"add-no-scope": add_no_scope,
|
|
"list-json": list_json,
|
|
}
|
|
|
|
if __name__ == "__main__":
|
|
cmd = sys.argv[1] if len(sys.argv) > 1 else None
|
|
if cmd not in COMMANDS:
|
|
print(f"Unknown command: {cmd}", file=sys.stderr)
|
|
print(f"Available: {', '.join(sorted(COMMANDS))}", file=sys.stderr)
|
|
sys.exit(2)
|
|
COMMANDS[cmd]()
|