"""Helper script for project CLI Robot Framework integration tests. Usage: python robot/helper_project_cli.py """ from __future__ import annotations import sys from sqlalchemy import create_engine from sqlalchemy.orm import sessionmaker from cleveragents.application.services.resource_registry_service import ( ResourceRegistryService, ) from cleveragents.domain.models.core.project import ( NamespacedProject, parse_namespaced_name, ) from cleveragents.infrastructure.database.models import Base from cleveragents.infrastructure.database.repositories import ( NamespacedProjectRepository, ProjectResourceLinkRepository, ) def _setup_db() -> tuple[ NamespacedProjectRepository, ProjectResourceLinkRepository, ResourceRegistryService, ]: """Create an in-memory SQLite DB and return repos + service.""" engine = create_engine("sqlite:///:memory:", echo=False) Base.metadata.create_all(engine) session = sessionmaker(bind=engine, expire_on_commit=False)() class _NoClose: def __init__(self, s: object) -> None: object.__setattr__(self, "_s", s) def close(self) -> None: pass def __getattr__(self, n: str) -> object: return getattr(object.__getattribute__(self, "_s"), n) wrapper = _NoClose(session) def factory() -> object: return wrapper proj_repo = NamespacedProjectRepository(session_factory=factory) link_repo = ProjectResourceLinkRepository(session_factory=factory) svc = ResourceRegistryService(session_factory=factory) svc.bootstrap_builtin_types() return proj_repo, link_repo, svc def test_project_crud() -> None: """Create, list, show, delete a project.""" proj_repo, _link_repo, _svc = _setup_db() # Create parsed = parse_namespaced_name("my-project") proj = NamespacedProject( name=parsed.name, namespace=parsed.namespace, description="Robot test project", ) proj_repo.create(proj) # List projects = proj_repo.list_projects() if len(projects) != 1: raise AssertionError(f"Expected 1 project, got {len(projects)}") # Show fetched = proj_repo.get("local/my-project") if fetched.namespaced_name != "local/my-project": raise AssertionError(f"Name mismatch: {fetched.namespaced_name}") # Delete deleted = proj_repo.delete("local/my-project") if not deleted: raise AssertionError("Delete returned False") projects_after = proj_repo.list_projects() if len(projects_after) != 0: raise AssertionError(f"Expected 0 projects, got {len(projects_after)}") print("project-crud-ok") def test_link_lifecycle() -> None: """Create project, link resource, unlink, delete.""" proj_repo, link_repo, svc = _setup_db() # Create project parsed = parse_namespaced_name("link-test") proj = NamespacedProject( name=parsed.name, namespace=parsed.namespace, description="Link test", ) proj_repo.create(proj) # Register resource res = svc.register_resource( type_name="git-checkout", name="local/test-repo", location="/tmp/test", description="Test repo", ) # Link link = link_repo.create_link( project_name="local/link-test", resource_id=res.resource_id, ) # Verify link links = link_repo.list_links("local/link-test") if len(links) != 1: raise AssertionError(f"Expected 1 link, got {len(links)}") # Unlink link_repo.remove_link(str(link.link_id)) links_after = link_repo.list_links("local/link-test") if len(links_after) != 0: raise AssertionError(f"Expected 0 links, got {len(links_after)}") # Delete project proj_repo.delete("local/link-test") print("link-lifecycle-ok") def test_spec_dict() -> None: """Verify _project_spec_dict output keys.""" from cleveragents.cli.commands.project import _project_spec_dict proj_repo, _link_repo, _svc = _setup_db() parsed = parse_namespaced_name("dict-test") proj = NamespacedProject( name=parsed.name, namespace=parsed.namespace, description="Dict test", ) proj_repo.create(proj) fetched = proj_repo.get("local/dict-test") data = _project_spec_dict(fetched) expected_keys = { "namespaced_name", "namespace", "name", "description", "linked_resources", "created_at", "updated_at", } if set(data.keys()) != expected_keys: raise AssertionError(f"Key mismatch: {set(data.keys())} != {expected_keys}") print("spec-dict-ok") TESTS = { "project-crud": test_project_crud, "link-lifecycle": test_link_lifecycle, "spec-dict": test_spec_dict, } if __name__ == "__main__": if len(sys.argv) < 2 or sys.argv[1] not in TESTS: print(f"Usage: {sys.argv[0]} <{'|'.join(TESTS)}>", file=sys.stderr) sys.exit(2) try: TESTS[sys.argv[1]]() except Exception as exc: print(f"FAIL: {exc}", file=sys.stderr) sys.exit(1)