from __future__ import annotations import json import os import tempfile from typing import Any from behave import given, then, when from behave.runner import Context from cleveragents.domain.models.core.plan import ExecutionEnvPriority from cleveragents.domain.models.core.project import ContextConfig # --------------------------------------------------------------------------- # Domain model steps # --------------------------------------------------------------------------- @given('I create a ContextConfig with execution_env_priority "{priority}"') def step_create_cc_with_priority(context: Context, priority: str) -> None: context.cc = ContextConfig(execution_env_priority=priority) @given("I create a default ContextConfig") def step_create_default_cc(context: Context) -> None: context.cc = ContextConfig() @then('the context config execution_env_priority should be "{expected}"') def step_check_cc_priority(context: Context, expected: str) -> None: assert context.cc.execution_env_priority == expected @then("the context config execution_env_priority should be None") def step_check_cc_priority_none(context: Context) -> None: assert context.cc.execution_env_priority is None # --------------------------------------------------------------------------- # Enum steps # --------------------------------------------------------------------------- @then('the ExecutionEnvPriority enum should have "{value}"') def step_check_eep_enum(context: Context, value: str) -> None: assert value in [e.value for e in ExecutionEnvPriority] # --------------------------------------------------------------------------- # CLI simulation helpers # --------------------------------------------------------------------------- def _setup_test_db(context: Context, project_name: str) -> Any: """Create a temporary SQLite DB with the ns_projects table.""" from sqlalchemy import Column, String, Text, create_engine from sqlalchemy.orm import Session, declarative_base, sessionmaker fd, db_path = tempfile.mkstemp(suffix=".db") os.close(fd) context._eep_db_path = db_path engine = create_engine(f"sqlite:///{db_path}") Base = declarative_base() class NsProject(Base): # type: ignore[misc] __tablename__ = "ns_projects" namespaced_name = Column(String(255), primary_key=True) context_policy_json = Column(Text, nullable=True) Base.metadata.create_all(engine) factory = sessionmaker(bind=engine, expire_on_commit=False) session: Session = factory() session.execute( NsProject.__table__.insert().values( namespaced_name=project_name, context_policy_json=None, ) ) session.commit() session.close() context._eep_session_factory = factory return factory @given('I have a test project "{name}"') def step_setup_test_project(context: Context, name: str) -> None: _setup_test_db(context, name) context._eep_project_name = name def _load_blob(context: Context) -> dict[str, Any]: """Load the raw policy JSON from the test DB.""" from sqlalchemy import text session = context._eep_session_factory() try: row = session.execute( text( "SELECT context_policy_json FROM ns_projects " "WHERE namespaced_name = :ns" ), {"ns": context._eep_project_name}, ).fetchone() if row is None or row[0] is None: return {} return json.loads(row[0]) finally: session.close() def _save_blob(context: Context, blob: dict[str, Any]) -> None: """Save raw policy JSON to the test DB.""" from sqlalchemy import text session = context._eep_session_factory() try: session.execute( text( "UPDATE ns_projects SET context_policy_json = :blob " "WHERE namespaced_name = :ns" ), {"blob": json.dumps(blob), "ns": context._eep_project_name}, ) session.commit() finally: session.close() # --------------------------------------------------------------------------- # CLI validation steps # --------------------------------------------------------------------------- @when('I call project context set with execution-env-priority "{priority}"') def step_call_set_with_priority(context: Context, priority: str) -> None: context._eep_error = None try: ExecutionEnvPriority(priority.lower()) # Valid -- persist it blob = _load_blob(context) blob["execution_env_priority"] = priority.lower() _save_blob(context, blob) except ValueError as exc: context._eep_error = exc @then("a CLI error should be raised for invalid priority") def step_cli_error_raised(context: Context) -> None: assert context._eep_error is not None @then('the project priority should be persisted as "{expected}"') def step_check_persisted_priority(context: Context, expected: str) -> None: blob = _load_blob(context) assert blob.get("execution_env_priority") == expected # --------------------------------------------------------------------------- # Persistence round-trip steps # --------------------------------------------------------------------------- @when('I set execution-environment "{env}" and priority "{priority}"') def step_set_both(context: Context, env: str, priority: str) -> None: blob = _load_blob(context) blob["execution_environment"] = env blob["execution_env_priority"] = priority _save_blob(context, blob) @then('the persisted blob should have execution_environment "{expected}"') def step_blob_has_ee(context: Context, expected: str) -> None: blob = _load_blob(context) assert blob.get("execution_environment") == expected @then('the persisted blob should have execution_env_priority "{expected}"') def step_blob_has_eep(context: Context, expected: str) -> None: blob = _load_blob(context) assert blob.get("execution_env_priority") == expected @when('I set execution-environment "{env}" first') def step_set_ee_first(context: Context, env: str) -> None: blob = _load_blob(context) blob["execution_environment"] = env _save_blob(context, blob) @when('I set execution-env-priority "{priority}" second') def step_set_eep_second(context: Context, priority: str) -> None: blob = _load_blob(context) blob["execution_env_priority"] = priority _save_blob(context, blob) @then('the persisted blob should still have execution_environment "{expected}"') def step_blob_still_has_ee(context: Context, expected: str) -> None: blob = _load_blob(context) assert blob.get("execution_environment") == expected, ( f"Expected '{expected}', got '{blob.get('execution_environment')}'" )