fix(cli): add @tdd_issue_1500 tag and Robot Framework enforcement tests
CI / load-versions (pull_request) Successful in 13s
CI / push-validation (pull_request) Successful in 20s
CI / quality (pull_request) Failing after 26s
CI / lint (pull_request) Successful in 44s
CI / build (pull_request) Successful in 34s
CI / helm (pull_request) Successful in 40s
CI / typecheck (pull_request) Successful in 1m16s
CI / security (pull_request) Successful in 4m49s
CI / unit_tests (pull_request) Successful in 10m42s
CI / coverage (pull_request) Has been skipped
CI / docker (pull_request) Successful in 2m7s
CI / integration_tests (pull_request) Successful in 16m3s
CI / status-check (pull_request) Failing after 1s

- Add @tdd_issue_1500 to all 4 scenarios in
  features/actor_add_update_enforcement.feature so regression
  tests are correctly associated with the closed issue.
- Add robot/actor_add_update_enforcement.robot with 3 integration
  test cases: reject existing actor without --update (exit 1),
  accept existing actor with --update (exit 0), accept new actor
  without --update (exit 0).
- Add robot/helper_actor_add_update_enforcement.py with mock-based
  helper functions for all three test cases.

ISSUES CLOSED: #1500
This commit is contained in:
2026-06-19 01:51:07 -04:00
committed by Forgejo
parent 17ded1c83c
commit 3ccf5dffdd
3 changed files with 209 additions and 4 deletions
@@ -5,7 +5,7 @@ Feature: agents actor add enforces --update flag for existing actors
I want `agents actor add` to fail with a clear error when re-adding an existing actor
So that I cannot accidentally overwrite actor configurations without explicit intent
@tdd_issue @tdd_issue_2609 @tdd_issue_4178
@tdd_issue @tdd_issue_1500 @tdd_issue_2609 @tdd_issue_4178
Scenario: Re-adding an existing actor without --update fails with error panel
Given an actor add CLI runner where the actor already exists
When I run actor add without the --update flag
@@ -14,7 +14,7 @@ Feature: agents actor add enforces --update flag for existing actors
And the actor-add-enforcement output should contain "Use --update to replace the existing actor definition"
And the actor-add-enforcement output should contain the registration timestamp
@tdd_issue @tdd_issue_2609 @tdd_issue_4178
@tdd_issue @tdd_issue_1500 @tdd_issue_2609 @tdd_issue_4178
Scenario: Re-adding an existing actor without --update shows error status line
Given an actor add CLI runner where the actor already exists
When I run actor add without the --update flag
@@ -22,14 +22,14 @@ Feature: agents actor add enforces --update flag for existing actors
And the actor-add-enforcement output should contain "Actor already registered"
And the actor-add-enforcement output should contain "use --update to replace"
@tdd_issue @tdd_issue_2609 @tdd_issue_4178
@tdd_issue @tdd_issue_1500 @tdd_issue_2609 @tdd_issue_4178
Scenario: Re-adding an existing actor with --update succeeds
Given an actor add CLI runner where the actor already exists
When I run actor add with the --update flag
Then the actor-add-enforcement exit code should be 0
And the actor-add-enforcement output should contain "Actor updated"
@tdd_issue @tdd_issue_2609 @tdd_issue_4178
@tdd_issue @tdd_issue_1500 @tdd_issue_2609 @tdd_issue_4178
Scenario: Adding a new actor without --update succeeds
Given an actor add CLI runner where the actor does not exist
When I run actor add without the --update flag
+36
View File
@@ -0,0 +1,36 @@
*** Settings ***
Documentation Integration tests for actor add --update flag enforcement (issue #1500)
Resource ${CURDIR}/common.resource
Suite Setup Setup Test Environment
Suite Teardown Cleanup Test Environment
*** Variables ***
${HELPER} ${CURDIR}/helper_actor_add_update_enforcement.py
*** Test Cases ***
Actor Add Existing Actor Without Update Flag Fails
[Documentation] Verify that actor add rejects re-adding an existing actor without --update
[Tags] tdd_issue tdd_issue_1500
${result}= Run Process ${PYTHON} ${HELPER} reject-existing-without-update cwd=${WORKSPACE}
Log ${result.stdout}
Log ${result.stderr}
Should Be Equal As Integers ${result.rc} 0
Should Contain ${result.stdout} actor-add-reject-existing-ok
Actor Add Existing Actor With Update Flag Succeeds
[Documentation] Verify that actor add with --update on an existing actor succeeds
[Tags] tdd_issue tdd_issue_1500
${result}= Run Process ${PYTHON} ${HELPER} accept-existing-with-update cwd=${WORKSPACE}
Log ${result.stdout}
Log ${result.stderr}
Should Be Equal As Integers ${result.rc} 0
Should Contain ${result.stdout} actor-add-accept-update-ok
Actor Add New Actor Without Update Flag Succeeds
[Documentation] Verify that actor add on a new actor succeeds without --update
[Tags] tdd_issue tdd_issue_1500
${result}= Run Process ${PYTHON} ${HELPER} accept-new-without-update cwd=${WORKSPACE}
Log ${result.stdout}
Log ${result.stderr}
Should Be Equal As Integers ${result.rc} 0
Should Contain ${result.stdout} actor-add-accept-new-ok
@@ -0,0 +1,169 @@
"""Helper script for actor add --update flag enforcement Robot tests (issue #1500).
Tests that ``agents actor add`` rejects re-adding an existing actor without
the --update flag, and succeeds when --update is provided or the actor is new.
"""
from __future__ import annotations
import json
import sys
import tempfile
from datetime import datetime
from pathlib import Path
from typing import Any
from unittest.mock import MagicMock, patch
from typer.testing import CliRunner
from cleveragents.cli.commands.actor import app as actor_app
from cleveragents.core.exceptions import NotFoundError
from cleveragents.domain.models.core.actor import Actor
def _make_actor(
*,
name: str = "local/existing-actor",
provider: str = "openai",
model: str = "gpt-4",
config: dict[str, Any] | None = None,
updated_at: datetime | None = None,
) -> Actor:
blob = config or {}
return Actor(
id=1,
name=name,
provider=provider,
model=model,
config_blob=blob,
config_hash=Actor.compute_hash(blob),
unsafe=False,
is_built_in=False,
is_default=False,
updated_at=updated_at or datetime(2026, 2, 7, 14, 22, 0),
)
def _write_config(name: str) -> Path:
config_data: dict[str, Any] = {
"name": name,
"provider": "openai",
"model": "gpt-4",
}
with tempfile.NamedTemporaryFile(
delete=False, suffix=".json", mode="w", encoding="utf-8"
) as handle:
json.dump(config_data, handle)
handle.flush()
return Path(handle.name)
def test_reject_existing_without_update() -> None:
"""Re-adding an existing actor without --update must exit 1 with an error panel."""
actor_name = "local/existing-actor"
config_path = _write_config(actor_name)
existing = _make_actor(name=actor_name, updated_at=datetime(2026, 2, 7, 14, 22, 0))
try:
runner = CliRunner()
with patch("cleveragents.cli.commands.actor._get_services") as mock_svc:
registry = MagicMock()
registry.get_actor.return_value = existing
mock_svc.return_value = (MagicMock(), registry)
result = runner.invoke(
actor_app,
["add", actor_name, "--config", str(config_path)],
)
finally:
config_path.unlink(missing_ok=True)
assert result.exit_code == 1, (
f"Expected exit code 1 but got {result.exit_code}.\nOutput:\n{result.output}"
)
assert "Actor already exists" in result.output, (
f"Expected 'Actor already exists' in output:\n{result.output}"
)
assert "Use --update to replace" in result.output, (
f"Expected 'Use --update to replace' in output:\n{result.output}"
)
print("actor-add-reject-existing-ok")
def test_accept_existing_with_update() -> None:
"""Re-adding an existing actor with --update must exit 0 and show
'Actor updated'."""
actor_name = "local/existing-actor"
config_path = _write_config(actor_name)
existing = _make_actor(name=actor_name, updated_at=datetime(2026, 2, 7, 14, 22, 0))
updated = _make_actor(name=actor_name, updated_at=datetime(2026, 2, 7, 14, 22, 0))
try:
runner = CliRunner()
with patch("cleveragents.cli.commands.actor._get_services") as mock_svc:
registry = MagicMock()
registry.get_actor.return_value = existing
registry.upsert_actor.return_value = updated
mock_svc.return_value = (MagicMock(), registry)
result = runner.invoke(
actor_app,
["add", actor_name, "--config", str(config_path), "--update"],
)
finally:
config_path.unlink(missing_ok=True)
assert result.exit_code == 0, (
f"Expected exit code 0 but got {result.exit_code}.\nOutput:\n{result.output}"
)
assert "Actor updated" in result.output, (
f"Expected 'Actor updated' in output:\n{result.output}"
)
print("actor-add-accept-update-ok")
def test_accept_new_without_update() -> None:
"""Adding a brand-new actor without --update must exit 0 and show 'Actor added'."""
actor_name = "local/new-actor"
config_path = _write_config(actor_name)
new_actor = _make_actor(name=actor_name)
try:
runner = CliRunner()
with patch("cleveragents.cli.commands.actor._get_services") as mock_svc:
registry = MagicMock()
registry.get_actor.side_effect = NotFoundError(
resource_type="actor", resource_id=actor_name
)
registry.upsert_actor.return_value = new_actor
mock_svc.return_value = (MagicMock(), registry)
result = runner.invoke(
actor_app,
["add", actor_name, "--config", str(config_path)],
)
finally:
config_path.unlink(missing_ok=True)
assert result.exit_code == 0, (
f"Expected exit code 0 but got {result.exit_code}.\nOutput:\n{result.output}"
)
assert "Actor added" in result.output, (
f"Expected 'Actor added' in output:\n{result.output}"
)
print("actor-add-accept-new-ok")
def main() -> None:
command = sys.argv[1] if len(sys.argv) > 1 else ""
dispatch = {
"reject-existing-without-update": test_reject_existing_without_update,
"accept-existing-with-update": test_accept_existing_with_update,
"accept-new-without-update": test_accept_new_without_update,
}
fn = dispatch.get(command)
if fn is None:
print(f"Unknown command: {command!r}", file=sys.stderr)
sys.exit(1)
fn()
if __name__ == "__main__":
main()