Files
temp/features/steps/plan_resume_service_coverage_boost_steps.py
freemo a808c395f9 test(coverage): add Behave BDD tests to improve unit test coverage across 53 source modules
Add 53 new .feature files and corresponding step definition files targeting
uncovered lines identified in build/coverage.xml. Fix AmbiguousStep conflicts
in 7 pre-existing step files by disambiguating step text.

New tests cover: ACP clients/facade, actor CLI/config, application container,
ACMS service/strategies, async worker, automation profile CLI, autonomy
guardrail, bridge, change model, config CLI/service, context service,
cross-plan correction, database models, decision service, decomposition
clustering/service, discovery handler, langchain chat provider, langgraph
nodes, materializers, multi-project service, plan apply/CLI/lifecycle/model/
preflight/resume/service, PostgreSQL analyzer, project CLI/context CLI,
provider registry, reactive application/route, repositories, resolver handler,
resource registry service, resume model, retry patterns, sandbox protocol,
server CLI, skill CLI/service, skills registry, subplan execution/service,
system CLI, UKO loader, UoW, and YAML template engine.

Closes #645
2026-03-09 13:01:58 -04:00

203 lines
6.8 KiB
Python

"""Step definitions for Plan Resume Service coverage boost tests.
Targets uncovered validation-error branches in PlanResumeService:
- Line 75: __init__ with None lifecycle_service
- Line 93: get_resume_metadata with empty plan_id
- Line 186: build_resume_summary with empty plan_id
- Line 303: record_step_checkpoint with empty plan_id
- Line 305: record_step_checkpoint with negative step_index
- Line 307: record_step_checkpoint with empty decision_id
- Line 309: record_step_checkpoint with empty step_text
- Line 354: record_shutdown with empty plan_id
- Line 384: set_total_steps with negative total
"""
from behave import given, then, when
from behave.runner import Context
from ulid import ULID
from cleveragents.application.services.plan_lifecycle_service import (
PlanLifecycleService,
)
from cleveragents.application.services.plan_resume_service import (
PlanResumeService,
)
from cleveragents.config.settings import Settings
from cleveragents.core.exceptions import ValidationError
from cleveragents.domain.models.core.plan import (
ProjectLink,
)
# ---- Given steps ----
@given("I have a coverage-boost PlanResumeService")
def step_create_coverage_boost_service(context: Context) -> None:
"""Create a lifecycle service and a PlanResumeService for coverage tests."""
settings = Settings()
context.cb_lifecycle = PlanLifecycleService(settings=settings)
context.cb_resume = PlanResumeService(lifecycle_service=context.cb_lifecycle)
context.cb_error = None
context.cb_plan_id = None
@given("I have a coverage-boost plan in execute phase")
def step_create_coverage_boost_plan(context: Context) -> None:
"""Create a plan in execute/processing state for checkpoint tests."""
action_name = f"local/cb-test-{ULID()!s}"[:30].lower()
context.cb_lifecycle.create_action(
name=action_name,
description="Coverage boost test action",
definition_of_done="Step 1\nStep 2",
strategy_actor="local/stub-strategy",
execution_actor="local/stub-execute",
)
plan = context.cb_lifecycle.use_action(
action_name=action_name,
project_links=[ProjectLink(project_name="local/cb-proj")],
)
plan_id = plan.identity.plan_id
# Advance to execute/processing
context.cb_lifecycle.start_strategize(plan_id)
p = context.cb_lifecycle.get_plan(plan_id)
p.decision_root_id = str(ULID())
context.cb_lifecycle._commit_plan(p)
context.cb_lifecycle.complete_strategize(plan_id)
context.cb_lifecycle.execute_plan(plan_id)
context.cb_lifecycle.start_execute(plan_id)
context.cb_plan_id = plan_id
# ---- When steps ----
@when("I try to create a PlanResumeService with None lifecycle_service")
def step_create_service_with_none(context: Context) -> None:
"""Attempt to create PlanResumeService with None."""
context.cb_error = None
try:
PlanResumeService(lifecycle_service=None) # type: ignore[arg-type]
except ValidationError as exc:
context.cb_error = exc
@when("I try to get resume metadata with empty plan_id")
def step_get_metadata_empty_id(context: Context) -> None:
"""Attempt to get resume metadata with empty string."""
context.cb_error = None
try:
context.cb_resume.get_resume_metadata("")
except ValidationError as exc:
context.cb_error = exc
@when("I try to build resume summary with empty plan_id")
def step_build_summary_empty_id(context: Context) -> None:
"""Attempt to build resume summary with empty string."""
context.cb_error = None
try:
context.cb_resume.build_resume_summary("")
except ValidationError as exc:
context.cb_error = exc
@when("I try to record a step checkpoint with empty plan_id")
def step_checkpoint_empty_plan_id(context: Context) -> None:
"""Attempt to record checkpoint with empty plan_id."""
context.cb_error = None
try:
context.cb_resume.record_step_checkpoint(
plan_id="",
step_index=0,
decision_id="DEC001",
step_text="Do something",
)
except ValidationError as exc:
context.cb_error = exc
@when("I try to record a step checkpoint with step_index {index:d}")
def step_checkpoint_negative_index(context: Context, index: int) -> None:
"""Attempt to record checkpoint with given step_index."""
context.cb_error = None
try:
context.cb_resume.record_step_checkpoint(
plan_id=context.cb_plan_id,
step_index=index,
decision_id="DEC001",
step_text="Do something",
)
except ValidationError as exc:
context.cb_error = exc
@when("I try to record a step checkpoint with empty decision_id")
def step_checkpoint_empty_decision(context: Context) -> None:
"""Attempt to record checkpoint with empty decision_id."""
context.cb_error = None
try:
context.cb_resume.record_step_checkpoint(
plan_id=context.cb_plan_id,
step_index=0,
decision_id="",
step_text="Do something",
)
except ValidationError as exc:
context.cb_error = exc
@when("I try to record a step checkpoint with empty step_text")
def step_checkpoint_empty_step_text(context: Context) -> None:
"""Attempt to record checkpoint with empty step_text."""
context.cb_error = None
try:
context.cb_resume.record_step_checkpoint(
plan_id=context.cb_plan_id,
step_index=0,
decision_id="DEC001",
step_text="",
)
except ValidationError as exc:
context.cb_error = exc
@when("I try to record shutdown with empty plan_id")
def step_shutdown_empty_plan_id(context: Context) -> None:
"""Attempt to record shutdown with empty plan_id."""
context.cb_error = None
try:
context.cb_resume.record_shutdown("")
except ValidationError as exc:
context.cb_error = exc
@when("I try to set total steps to {total:d}")
def step_set_total_steps_negative(context: Context, total: int) -> None:
"""Attempt to set total steps to given value."""
context.cb_error = None
try:
context.cb_resume.set_total_steps(context.cb_plan_id, total)
except ValidationError as exc:
context.cb_error = exc
# ---- Then steps ----
@then('a coverage-boost ValidationError should be raised with message "{expected_msg}"')
def step_assert_validation_error_with_message(
context: Context, expected_msg: str
) -> None:
"""Assert a ValidationError was raised and contains the expected message."""
assert context.cb_error is not None, (
"Expected a ValidationError but none was raised"
)
assert isinstance(context.cb_error, ValidationError), (
f"Expected ValidationError, got {type(context.cb_error).__name__}"
)
assert expected_msg in str(context.cb_error), (
f"Expected message containing '{expected_msg}', got: {context.cb_error}"
)