"""Step definitions for container_id_flag.feature.""" from __future__ import annotations from typing import Any from behave import given, then, when from behave.runner import Context from sqlalchemy import create_engine from sqlalchemy.orm import sessionmaker from cleveragents.application.services.resource_registry_service import ( ResourceRegistryService, ) from cleveragents.domain.models.core.resource import PhysVirt, Resource from cleveragents.infrastructure.database.models import Base from cleveragents.resource.handlers.devcontainer import DevcontainerHandler class _NoClose: """Proxy that suppresses ``close()`` on an in-memory SQLite session. Without this, SQLAlchemy's ``session.close()`` releases the connection, destroying the in-memory database between operations. """ __slots__ = ("_s",) 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) @given("a resource registry service for container_id") def step_setup_registry(context: Context) -> None: engine = create_engine("sqlite:///:memory:", echo=False) Base.metadata.create_all(engine) session = sessionmaker(bind=engine, expire_on_commit=False)() wrapper = _NoClose(session) svc = ResourceRegistryService(session_factory=lambda: wrapper) svc.bootstrap_builtin_types() context.ci_service = svc @when('I add a container-instance with container-id "{cid}" for container_id') def step_add_with_container_id(context: Context, cid: str) -> None: properties: dict[str, Any] = {"container_id": cid} res = context.ci_service.register_resource( type_name="container-instance", name="local/test-ctr-id", description="Test container with ID", properties=properties, ) context.ci_resource = res @when( 'I validate container-instance with both container-id "{cid}" and image "{img}" for container_id' ) def step_validate_both_flags(context: Context, cid: str, img: str) -> None: """Simulate the CLI validation that rejects --container-id + --image together.""" error: str | None = None if cid is not None and img is not None: error = ( "--container-id and --image are mutually exclusive; " "provide one or the other, not both." ) context.ci_validation_error = error @when( "I validate container-instance with neither container-id nor image for container_id" ) def step_validate_neither_flag(context: Context) -> None: """Simulate the CLI validation that rejects container-instance with no image/id.""" context.ci_validation_error = ( "container-instance resources require either --image or --container-id." ) @when('I validate type "{type_name}" with container-id "{cid}" for container_id') def step_validate_wrong_type(context: Context, type_name: str, cid: str) -> None: """Simulate the CLI validation that rejects --container-id on non-container types.""" error: str | None = None if type_name != "container-instance": error = ( f"--container-id is only valid for container-instance resources, " f"not '{type_name}'" ) context.ci_validation_error = error @given('a resource with container_id "{cid}" in properties for container_id') def step_create_resource_with_container_id(context: Context, cid: str) -> None: """Create a minimal Resource domain object with container_id in properties.""" context.ci_handler_resource = Resource( resource_id="01ARZ3NDEKTSV4RRFFQ69G5FAV", name="local/test-handler-ctr", resource_type_name="container-instance", classification=PhysVirt.PHYSICAL, properties={"container_id": cid}, ) @when("I call _find_running_container for container_id") def step_call_find_running_container(context: Context) -> None: """Call DevcontainerHandler._find_running_container with the test resource.""" context.ci_handler_result = DevcontainerHandler._find_running_container( context.ci_handler_resource ) @then('the container_id resource should have container_id "{expected}"') def step_check_container_id_stored(context: Context, expected: str) -> None: resource = context.ci_resource assert resource.properties.get("container_id") == expected, ( f"Expected container_id '{expected}', " f"got: {resource.properties.get('container_id')!r}" ) @then('container_id validation should fail with "{message}"') def step_validation_should_fail(context: Context, message: str) -> None: error = context.ci_validation_error assert error is not None, "Expected a validation error but none was set" assert message.lower() in error.lower(), ( f"Expected '{message}' in validation error, got: {error!r}" ) @then('the container_id result should be "{expected}"') def step_check_handler_result(context: Context, expected: str) -> None: result = context.ci_handler_result assert result == expected, ( f"Expected _find_running_container to return '{expected}', got: {result!r}" )