*** Settings *** Documentation Resource DAG Linking and Discovery Tests Library Process Library OperatingSystem *** Test Cases *** Link Child And Verify Tree [Documentation] Link a child resource and verify it appears in children list ${script}= Catenate SEPARATOR=\n ... import json ... from datetime import datetime, UTC ... from sqlalchemy import create_engine, event ... from sqlalchemy.pool import StaticPool ... from sqlalchemy.orm import sessionmaker ... from sqlalchemy.pool import StaticPool ... from cleveragents.infrastructure.database.models import Base ... from cleveragents.infrastructure.database.repositories import ResourceTypeRepository, ResourceRepository ... from cleveragents.domain.models.core.resource_type import ResourceTypeSpec, ResourceKind, SandboxStrategy ... from cleveragents.domain.models.core.resource import Resource, PhysVirt, ResourceCapabilities ... engine = create_engine("sqlite://", connect_args={"check_same_thread": False}, poolclass=StaticPool) ... @event.listens_for(engine, "connect") ... def _fk(conn, _): conn.cursor().execute("PRAGMA foreign_keys=ON") ... Base.metadata.create_all(engine) ... factory = sessionmaker(bind=engine) ... shared_session = factory() ... rt_repo = ResourceTypeRepository(lambda: shared_session) ... res_repo = ResourceRepository(lambda: shared_session) ... parent_spec = ResourceTypeSpec(name="robot/dag-parent", description="Parent", resource_kind=ResourceKind.PHYSICAL, sandbox_strategy=SandboxStrategy.NONE, user_addable=True, cli_args=[], parent_types=[], child_types=["robot/dag-child"], auto_discovery=None, equivalence=None, handler=None, capabilities={"read": True, "write": True, "sandbox": True, "checkpoint": False}, built_in=False) ... child_spec = ResourceTypeSpec(name="robot/dag-child", description="Child", resource_kind=ResourceKind.PHYSICAL, sandbox_strategy=SandboxStrategy.NONE, user_addable=True, cli_args=[], parent_types=[], child_types=[], auto_discovery=None, equivalence=None, handler=None, capabilities={"read": True, "write": True, "sandbox": True, "checkpoint": False}, built_in=False) ... rt_repo.create(parent_spec) ... rt_repo.create(child_spec) ... p = Resource(resource_id="01HDAGR0B0T0000000PARENT01", name=None, resource_type_name="robot/dag-parent", classification=PhysVirt.PHYSICAL, properties={}, location=None, capabilities=ResourceCapabilities(), created_at=datetime.now(tz=UTC), updated_at=datetime.now(tz=UTC)) ... c = Resource(resource_id="01HDAGR0B0T00000CHXND00001", name=None, resource_type_name="robot/dag-child", classification=PhysVirt.PHYSICAL, properties={}, location=None, capabilities=ResourceCapabilities(), created_at=datetime.now(tz=UTC), updated_at=datetime.now(tz=UTC)) ... res_repo.create(p) ... res_repo.create(c) ... res_repo.link_child("01HDAGR0B0T0000000PARENT01", "01HDAGR0B0T00000CHXND00001") ... children = res_repo.get_children("01HDAGR0B0T0000000PARENT01") ... assert len(children) == 1, f"Expected 1 child, got {len(children)}" ... assert children[0].resource_id == "01HDAGR0B0T00000CHXND00001" ... shared_session.close() ... print("Link child and verify tree passed") ${result}= Run Process ${PYTHON} -c ${script} timeout=60s on_timeout=kill Should Be Equal As Integers ${result.rc} 0 Link test failed: ${result.stderr} Should Contain ${result.stdout} Link child and verify tree passed Cycle Detection Rejects A To B To A [Documentation] Linking A->B then B->A should raise CycleDetectedError ${script}= Catenate SEPARATOR=\n ... from datetime import datetime, UTC ... from sqlalchemy import create_engine, event ... from sqlalchemy.pool import StaticPool ... from sqlalchemy.orm import sessionmaker ... from sqlalchemy.pool import StaticPool ... from cleveragents.infrastructure.database.models import Base ... from cleveragents.infrastructure.database.repositories import ResourceTypeRepository, ResourceRepository, CycleDetectedError ... from cleveragents.domain.models.core.resource_type import ResourceTypeSpec, ResourceKind, SandboxStrategy ... from cleveragents.domain.models.core.resource import Resource, PhysVirt, ResourceCapabilities ... engine = create_engine("sqlite://", connect_args={"check_same_thread": False}, poolclass=StaticPool) ... @event.listens_for(engine, "connect") ... def _fk(conn, _): conn.cursor().execute("PRAGMA foreign_keys=ON") ... Base.metadata.create_all(engine) ... factory = sessionmaker(bind=engine) ... shared_session = factory() ... rt_repo = ResourceTypeRepository(lambda: shared_session) ... res_repo = ResourceRepository(lambda: shared_session) ... spec_a = ResourceTypeSpec(name="robot/cycle-a", description="Cycle A", resource_kind=ResourceKind.PHYSICAL, sandbox_strategy=SandboxStrategy.NONE, user_addable=True, cli_args=[], parent_types=[], child_types=["robot/cycle-b"], auto_discovery=None, equivalence=None, handler=None, capabilities={"read": True, "write": True, "sandbox": True, "checkpoint": False}, built_in=False) ... spec_b = ResourceTypeSpec(name="robot/cycle-b", description="Cycle B", resource_kind=ResourceKind.PHYSICAL, sandbox_strategy=SandboxStrategy.NONE, user_addable=True, cli_args=[], parent_types=[], child_types=["robot/cycle-a"], auto_discovery=None, equivalence=None, handler=None, capabilities={"read": True, "write": True, "sandbox": True, "checkpoint": False}, built_in=False) ... rt_repo.create(spec_a) ... rt_repo.create(spec_b) ... a = Resource(resource_id="01HDAGCYC000000000000000A1", name=None, resource_type_name="robot/cycle-a", classification=PhysVirt.PHYSICAL, properties={}, location=None, capabilities=ResourceCapabilities(), created_at=datetime.now(tz=UTC), updated_at=datetime.now(tz=UTC)) ... b = Resource(resource_id="01HDAGCYC000000000000000B1", name=None, resource_type_name="robot/cycle-b", classification=PhysVirt.PHYSICAL, properties={}, location=None, capabilities=ResourceCapabilities(), created_at=datetime.now(tz=UTC), updated_at=datetime.now(tz=UTC)) ... res_repo.create(a) ... res_repo.create(b) ... res_repo.link_child("01HDAGCYC000000000000000A1", "01HDAGCYC000000000000000B1") ... try: ... ${SPACE * 4}res_repo.link_child("01HDAGCYC000000000000000B1", "01HDAGCYC000000000000000A1") ... ${SPACE * 4}assert False, "Should have raised CycleDetectedError" ... except CycleDetectedError: ... ${SPACE * 4}print("Cycle detection passed") ... finally: ... ${SPACE * 4}shared_session.close() ${result}= Run Process ${PYTHON} -c ${script} timeout=60s on_timeout=kill Should Be Equal As Integers ${result.rc} 0 Cycle test failed: ${result.stderr} Should Contain ${result.stdout} Cycle detection passed Auto Discover Children [Documentation] Auto-discover creates child resources per type rules ${script}= Catenate SEPARATOR=\n ... import json ... from datetime import datetime, UTC ... from sqlalchemy import create_engine, event ... from sqlalchemy.pool import StaticPool ... from sqlalchemy.orm import sessionmaker ... from sqlalchemy.pool import StaticPool ... from cleveragents.infrastructure.database.models import Base ... from cleveragents.infrastructure.database.repositories import ResourceTypeRepository, ResourceRepository ... from cleveragents.domain.models.core.resource_type import ResourceTypeSpec, ResourceKind, SandboxStrategy ... from cleveragents.domain.models.core.resource import Resource, PhysVirt, ResourceCapabilities ... engine = create_engine("sqlite://", connect_args={"check_same_thread": False}, poolclass=StaticPool) ... @event.listens_for(engine, "connect") ... def _fk(conn, _): conn.cursor().execute("PRAGMA foreign_keys=ON") ... Base.metadata.create_all(engine) ... factory = sessionmaker(bind=engine) ... shared_session = factory() ... rt_repo = ResourceTypeRepository(lambda: shared_session) ... res_repo = ResourceRepository(lambda: shared_session) ... parent_spec = ResourceTypeSpec(name="robot/disc-parent", description="Discoverer", resource_kind=ResourceKind.PHYSICAL, sandbox_strategy=SandboxStrategy.NONE, user_addable=True, cli_args=[], parent_types=[], child_types=["robot/disc-child"], auto_discovery={"enabled": True, "rules": [{"type": "robot/disc-child", "pattern": "*"}]}, equivalence=None, handler=None, capabilities={"read": True, "write": True, "sandbox": True, "checkpoint": False}, built_in=False) ... child_spec = ResourceTypeSpec(name="robot/disc-child", description="Discovered", resource_kind=ResourceKind.PHYSICAL, sandbox_strategy=SandboxStrategy.NONE, user_addable=True, cli_args=[], parent_types=[], child_types=[], auto_discovery=None, equivalence=None, handler=None, capabilities={"read": True, "write": True, "sandbox": True, "checkpoint": False}, built_in=False) ... rt_repo.create(parent_spec) ... rt_repo.create(child_spec) ... p = Resource(resource_id="01HDAGR0B0TDSC00PARENT0001", name=None, resource_type_name="robot/disc-parent", classification=PhysVirt.PHYSICAL, properties={}, location=None, capabilities=ResourceCapabilities(), created_at=datetime.now(tz=UTC), updated_at=datetime.now(tz=UTC)) ... res_repo.create(p) ... created = res_repo.auto_discover_children("01HDAGR0B0TDSC00PARENT0001") ... assert len(created) >= 1, f"Expected >=1 children, got {len(created)}" ... assert created[0].resource_type_name == "robot/disc-child" ... children = res_repo.get_children("01HDAGR0B0TDSC00PARENT0001") ... assert len(children) >= 1, f"Expected >=1 linked children, got {len(children)}" ... shared_session.close() ... print("Auto discover children passed") ${result}= Run Process ${PYTHON} -c ${script} timeout=60s on_timeout=kill Should Be Equal As Integers ${result.rc} 0 Auto discover test failed: ${result.stderr} Should Contain ${result.stdout} Auto discover children passed *** Keywords ***