Files
cleveragents-core/features/steps/persistence_robot_alignment_steps.py
T
brent.edwards ab8ed19aa7
CI / benchmark-publish (pull_request) Has been skipped
CI / quality (pull_request) Successful in 19s
CI / lint (pull_request) Failing after 22s
CI / build (pull_request) Successful in 27s
CI / typecheck (pull_request) Successful in 55s
CI / coverage (pull_request) Has been skipped
CI / benchmark-regression (pull_request) Has been skipped
CI / security (pull_request) Successful in 1m7s
CI / unit_tests (pull_request) Has been cancelled
CI / integration_tests (pull_request) Has been cancelled
CI / docker (pull_request) Has been cancelled
fix(tests): remove AutomationLevel references after legacy field removal
Master's refactor(automation) commit removed the AutomationLevel enum
and automation_level field from Plan. Update all behave steps, robot
helpers, and feature scenarios that referenced the removed type:

- cli_lifecycle_robot_alignment_steps.py: drop import and field assignment
- persistence_robot_alignment_steps.py: drop import and field assignment
- subplan_model_steps.py: drop import, parameter, and field assignment
- subplan_model.feature: replace automation level scenario with profile check
- helper_cli_lifecycle.py: drop import and field assignment
- helper_persistence_lifecycle.py: drop import, field assignment, and assertion
2026-02-20 20:34:29 +00:00

160 lines
5.4 KiB
Python

"""Step definitions for persistence_robot_alignment.feature.
Mirrors the Robot restart-simulation flow to keep unit/integration
persistence expectations aligned. Uses file-backed SQLite so the
close-reopen cycle exercises real disk persistence.
"""
from __future__ import annotations
import tempfile
from datetime import UTC, datetime
from pathlib import Path
from typing import Any
from behave import given, then, when
from behave.runner import Context
from sqlalchemy import create_engine
from sqlalchemy.orm import Session
from cleveragents.domain.models.core.action import Action, ActionState
from cleveragents.domain.models.core.plan import (
NamespacedName,
Plan,
PlanIdentity,
PlanPhase,
PlanTimestamps,
ProcessingState,
ProjectLink,
)
from cleveragents.infrastructure.database.models import init_database
from cleveragents.infrastructure.database.repositories import (
ActionRepository,
LifecyclePlanRepository,
)
def _phase_from_str(value: str) -> PlanPhase:
"""Convert a lowercase phase string to PlanPhase enum."""
return PlanPhase(value)
def _state_from_str(value: str) -> ProcessingState:
"""Convert a lowercase state string to ProcessingState enum."""
return ProcessingState(value)
@given("a fresh file-backed persistence alignment database")
def step_fresh_db(context: Context) -> None:
tmp_path: str = tempfile.mktemp(suffix=".db")
db_url: str = f"sqlite:///{tmp_path}"
engine: Any = init_database(db_url)
session: Session = Session(bind=engine)
context._pra_db_path = tmp_path
context._pra_session = session
context._pra_engine = engine
@given('a persistence alignment action "{name}"')
def step_create_action(context: Context, name: str) -> None:
session: Session = context._pra_session
factory = lambda: session # noqa: E731
now: datetime = datetime(2026, 2, 1, tzinfo=UTC)
action = Action(
namespaced_name=NamespacedName.parse(name),
description="Alignment test action",
definition_of_done="Restart assertions pass",
strategy_actor="local/strat",
execution_actor="local/exec",
state=ActionState.AVAILABLE,
created_at=now,
updated_at=now,
)
repo = ActionRepository(session_factory=factory)
repo.create(action)
session.commit()
context._pra_action_name = name
@given(
'a persistence alignment plan "{plan_id}" in phase "{phase}" with state "{state}"'
)
def step_create_plan(context: Context, plan_id: str, phase: str, state: str) -> None:
session: Session = context._pra_session
factory = lambda: session # noqa: E731
now: datetime = datetime(2026, 3, 1, tzinfo=UTC)
plan = Plan(
identity=PlanIdentity(plan_id=plan_id, attempt=1),
namespaced_name=NamespacedName(namespace="local", name="aligned-plan"),
action_name=context._pra_action_name,
description="Alignment test plan",
definition_of_done="Alignment pass",
phase=_phase_from_str(phase),
processing_state=_state_from_str(state),
strategy_actor="local/strat",
execution_actor="local/exec",
project_links=[ProjectLink(project_name="local/proj-aligned")],
timestamps=PlanTimestamps(created_at=now, updated_at=now),
created_by="alignment-test",
tags=["alignment"],
reusable=True,
read_only=False,
)
repo = LifecyclePlanRepository(session_factory=factory)
repo.create(plan)
session.commit()
@when("the persistence alignment database is closed and reopened")
def step_close_reopen(context: Context) -> None:
context._pra_session.close()
context._pra_engine.dispose()
db_url: str = f"sqlite:///{context._pra_db_path}"
engine2: Any = create_engine(db_url, echo=False)
session2: Session = Session(bind=engine2)
context._pra_session = session2
context._pra_engine = engine2
@then('the persistence alignment plan "{plan_id}" should exist')
def step_plan_exists(context: Context, plan_id: str) -> None:
session: Session = context._pra_session
factory = lambda: session # noqa: E731
repo = LifecyclePlanRepository(session_factory=factory)
plan = repo.get(plan_id)
assert plan is not None, f"Plan {plan_id} not found after reopen"
context._pra_plan = plan
@then('the persistence alignment plan phase should be "{phase}"')
def step_check_phase(context: Context, phase: str) -> None:
assert context._pra_plan.phase == _phase_from_str(phase), (
f"Expected phase {phase}, got {context._pra_plan.phase}"
)
@then('the persistence alignment plan processing state should be "{state}"')
def step_check_state(context: Context, state: str) -> None:
assert context._pra_plan.processing_state == _state_from_str(state), (
f"Expected state {state}, got {context._pra_plan.processing_state}"
)
@then('the persistence alignment plan description should be "{desc}"')
def step_check_desc(context: Context, desc: str) -> None:
assert context._pra_plan.description == desc, (
f"Expected '{desc}', got '{context._pra_plan.description}'"
)
@then("the persistence alignment plan should have {count:d} project link")
def step_check_links(context: Context, count: int) -> None:
actual: int = len(context._pra_plan.project_links)
assert actual == count, f"Expected {count} links, got {actual}"
# Clean up temp file
tmp_path: str = context._pra_db_path
context._pra_session.close()
context._pra_engine.dispose()
Path(tmp_path).unlink(missing_ok=True)