Files
temp/features/steps/project_exec_env_priority_steps.py
hamza.khyari 49015c6bee fix(cli): implement --execution-env-priority on project context set
Add --execution-env-priority flag to 'project context set' command,
enabling project-level execution environment priority per spec WF17.

- Add execution_env_priority field to ContextConfig domain model
- Validate flag value against ExecutionEnvPriority enum (fallback/override)
- Persist in context_policy_json, preserving existing execution_environment
- Display in 'project context show' Execution Environment section
- Merge with existing blob to avoid overwriting previously set fields

Tests: 9 Behave scenarios, 26 steps.

ISSUES CLOSED: #1079
2026-03-30 14:33:28 +00:00

206 lines
6.7 KiB
Python

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')}'"
)