Files
cleveragents-core/robot/helper_skill_registry.py
2026-02-21 16:30:40 +00:00

163 lines
4.9 KiB
Python

"""Helper script for Robot Framework skill registry smoke tests.
Usage:
python helper_skill_registry.py <command>
Commands:
register-and-get Register a skill and retrieve it
list-filter Register skills and list with namespace filter
update-skill Register and update a skill
duplicate-reject Verify duplicate skill names are rejected
remove-skill Register and remove a skill
"""
from __future__ import annotations
import sys
from pathlib import Path
# Ensure src is on the path
src_dir = str(Path(__file__).resolve().parents[1] / "src")
if src_dir not in sys.path:
sys.path.insert(0, src_dir)
from sqlalchemy import create_engine, event, text # noqa: E402
from sqlalchemy.orm import Session, sessionmaker # noqa: E402
from cleveragents.application.services.skill_registry_service import ( # noqa: E402
SkillRegistryService,
)
from cleveragents.domain.models.core.skill import Skill # noqa: E402
from cleveragents.infrastructure.database.models import Base # noqa: E402
from cleveragents.infrastructure.database.repositories import ( # noqa: E402
DuplicateSkillError,
SkillRepository,
)
def _enable_fk_pragma(dbapi_conn, _connection_record): # type: ignore[no-untyped-def]
"""Enable SQLite foreign key enforcement per connection."""
cursor = dbapi_conn.cursor()
cursor.execute("PRAGMA foreign_keys=ON")
cursor.close()
def _setup() -> tuple[SkillRegistryService, sessionmaker[Session]]:
"""Create an in-memory DB and return the service + session factory."""
engine = create_engine("sqlite:///:memory:", echo=False)
event.listen(engine, "connect", _enable_fk_pragma)
Base.metadata.create_all(engine)
factory: sessionmaker[Session] = sessionmaker(bind=engine)
repo = SkillRepository(session_factory=factory)
svc = SkillRegistryService(skill_repo=repo)
return svc, factory
def _commit(factory: sessionmaker[Session]) -> None:
"""Commit the pending transaction on the shared connection."""
session = factory()
try:
session.execute(text("SELECT 1"))
session.commit()
finally:
session.close()
def _make_skill(name: str, description: str = "Test skill") -> Skill:
return Skill(name=name, description=description)
def cmd_register_and_get() -> None:
svc, factory = _setup()
skill = _make_skill("local/test-tool", "A test skill")
svc.add_skill(skill)
_commit(factory)
result = svc.get_skill("local/test-tool")
assert result is not None, "Skill not found"
assert result.name == "local/test-tool"
print("skill-registry-ok")
def cmd_list_filter() -> None:
svc, factory = _setup()
svc.add_skill(_make_skill("local/tool-a", "Tool A"))
svc.add_skill(_make_skill("local/tool-b", "Tool B"))
svc.add_skill(_make_skill("devops/deploy", "Deploy"))
_commit(factory)
all_skills = svc.list_skills()
assert len(all_skills) == 3
local_skills = svc.list_skills(namespace="local")
assert len(local_skills) == 2
print("skill-list-ok")
def cmd_update_skill() -> None:
svc, factory = _setup()
svc.add_skill(_make_skill("local/updatable", "Original"))
_commit(factory)
updated = _make_skill("local/updatable", "Updated desc")
svc.update_skill(updated)
_commit(factory)
result = svc.get_skill("local/updatable")
assert result is not None
assert result.description == "Updated desc"
print("skill-update-ok")
def cmd_duplicate_reject() -> None:
svc, factory = _setup()
svc.add_skill(_make_skill("local/dup-test", "First"))
_commit(factory)
try:
svc.add_skill(_make_skill("local/dup-test", "Second"))
_commit(factory)
print("FAIL: should have raised DuplicateSkillError")
sys.exit(1)
except DuplicateSkillError:
print("skill-duplicate-reject-ok")
except Exception as exc:
# tenacity may wrap the error; unwrap if needed
cause = exc.__cause__ or exc
if isinstance(cause, DuplicateSkillError):
print("skill-duplicate-reject-ok")
else:
print(f"FAIL: unexpected {type(exc).__name__}: {exc}")
sys.exit(1)
def cmd_remove_skill() -> None:
svc, factory = _setup()
svc.add_skill(_make_skill("local/removable", "Removable"))
_commit(factory)
result = svc.remove_skill("local/removable")
_commit(factory)
assert result is True
check = svc.get_skill("local/removable")
assert check is None
print("skill-remove-ok")
COMMANDS = {
"register-and-get": cmd_register_and_get,
"list-filter": cmd_list_filter,
"update-skill": cmd_update_skill,
"duplicate-reject": cmd_duplicate_reject,
"remove-skill": cmd_remove_skill,
}
if __name__ == "__main__":
if len(sys.argv) < 2 or sys.argv[1] not in COMMANDS:
print(f"Usage: {sys.argv[0]} <{'|'.join(COMMANDS)}>", file=sys.stderr)
sys.exit(1)
COMMANDS[sys.argv[1]]()