051ee7c290
CI / benchmark-publish (pull_request) Has been skipped
CI / lint (pull_request) Successful in 21s
CI / quality (pull_request) Successful in 31s
CI / typecheck (pull_request) Successful in 47s
CI / security (pull_request) Successful in 52s
CI / build (pull_request) Successful in 56s
CI / e2e_tests (pull_request) Successful in 5m1s
CI / integration_tests (pull_request) Successful in 5m30s
CI / unit_tests (pull_request) Successful in 5m42s
CI / docker (pull_request) Successful in 58s
CI / coverage (pull_request) Successful in 7m35s
CI / build (push) Successful in 21s
CI / docker (push) Has been skipped
CI / benchmark-regression (pull_request) Failing after 49m24s
CI / lint (push) Successful in 22s
CI / quality (push) Successful in 39s
CI / security (push) Successful in 48s
CI / typecheck (push) Successful in 1m26s
CI / benchmark-regression (push) Has been skipped
CI / e2e_tests (push) Successful in 5m53s
CI / coverage (push) Successful in 9m4s
CI / benchmark-publish (push) Successful in 19m10s
CI / integration_tests (push) Failing after 19m18s
CI / unit_tests (push) Failing after 19m20s
Added 52 new .feature files and corresponding _steps.py files targeting previously uncovered code paths in the following areas: - TUI layer: app, commands, persona (state/schema/registry), widgets, input (shell_exec, reference_parser) - Application services: plan lifecycle/service/executor, session, project, repo indexing, correction, checkpoint, actor, llm_actors, strategy coordinator, resource file watcher, service retry wiring - CLI commands: session, resource, repl, plan, db, automation_profile - Domain models: retry_policy, resource_type, cost_budget, docker_compose_analyzer, detail_level, _sql_string_aware, _postgresql_helpers - Core: circuit_breaker, retry_service_patterns - Infrastructure: repositories, transaction_sandbox, strategy_registry, plugins/loader, container - Config: settings - Agents: plan_generation, context_analysis, auto_debug - A2A: facade All new tests follow the Behave/Gherkin BDD standard. Resolved step definition collisions with unique prefixes. Fixed Alembic fileConfig logger disabling issue (disable_existing_loggers=False). ISSUES CLOSED: #1068
279 lines
9.4 KiB
Python
279 lines
9.4 KiB
Python
"""Step definitions for db_cli_coverage.feature.
|
|
|
|
These steps target specific uncovered lines in cleveragents/cli/commands/db.py:
|
|
- Lines 60-64: migrate() — imports alembic, gets runner, calls revision, echoes
|
|
- Lines 85, 87: upgrade() with non-head revision — imports alembic, calls upgrade
|
|
- Line 94: upgrade() with non-rich format — echoes format_output
|
|
- Line 123: downgrade() with non-rich format — echoes format_output
|
|
- Line 148: current() with non-rich format — echoes format_output
|
|
- Lines 156, 158, 160, 161: history() with rich format
|
|
- Lines 163, 165-169: history() with non-rich format — ScriptDirectory walk
|
|
"""
|
|
|
|
from types import SimpleNamespace
|
|
from unittest.mock import MagicMock, patch
|
|
|
|
import alembic.command
|
|
import alembic.script
|
|
from behave import given, then, when
|
|
|
|
import cleveragents.cli.commands.db as db_module
|
|
from cleveragents.cli.commands.db import (
|
|
current,
|
|
downgrade,
|
|
history,
|
|
migrate,
|
|
upgrade,
|
|
)
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Background
|
|
# ---------------------------------------------------------------------------
|
|
@given("the db commands module is imported")
|
|
def step_db_module_imported(context):
|
|
"""Ensure the db module is importable."""
|
|
assert db_module is not None
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Mock setup helpers
|
|
# ---------------------------------------------------------------------------
|
|
def _make_mock_runner(current_revision="abc123def", pending=None):
|
|
"""Build a mock MigrationRunner with configurable behaviour."""
|
|
runner = MagicMock()
|
|
runner.get_current_revision.return_value = current_revision
|
|
runner.get_pending_migrations.return_value = pending or []
|
|
runner.alembic_cfg = MagicMock(name="alembic_cfg")
|
|
runner.init_or_upgrade = MagicMock()
|
|
return runner
|
|
|
|
|
|
def _install_runner_and_echo(context, mock_runner):
|
|
"""Shared helper: patch _get_runner and typer.echo, register cleanups."""
|
|
context.mock_runner = mock_runner
|
|
|
|
patcher1 = patch.object(db_module, "_get_runner", return_value=context.mock_runner)
|
|
patcher1.start()
|
|
context.add_cleanup(patcher1.stop)
|
|
|
|
context.echo_calls = []
|
|
patcher2 = patch.object(
|
|
db_module.typer, "echo", side_effect=lambda msg: context.echo_calls.append(msg)
|
|
)
|
|
patcher2.start()
|
|
context.add_cleanup(patcher2.stop)
|
|
|
|
|
|
@given("the migration runner is mocked")
|
|
def step_mock_runner(context):
|
|
_install_runner_and_echo(context, _make_mock_runner())
|
|
|
|
|
|
@given("the migration runner is mocked with pending migrations")
|
|
def step_mock_runner_with_pending(context):
|
|
_install_runner_and_echo(
|
|
context,
|
|
_make_mock_runner(current_revision="rev001", pending=["rev002", "rev003"]),
|
|
)
|
|
|
|
|
|
@given("the migration runner is mocked with no current revision")
|
|
def step_mock_runner_no_revision(context):
|
|
_install_runner_and_echo(
|
|
context,
|
|
_make_mock_runner(current_revision=None, pending=["rev001"]),
|
|
)
|
|
|
|
|
|
@given("alembic command module is mocked")
|
|
def step_mock_alembic_command(context):
|
|
"""Mock alembic.command functions in-place."""
|
|
p1 = patch.object(alembic.command, "revision", MagicMock())
|
|
p2 = patch.object(alembic.command, "upgrade", MagicMock())
|
|
p3 = patch.object(alembic.command, "downgrade", MagicMock())
|
|
p4 = patch.object(alembic.command, "history", MagicMock())
|
|
|
|
context.mock_alembic_revision = p1.start()
|
|
context.mock_alembic_upgrade = p2.start()
|
|
context.mock_alembic_downgrade = p3.start()
|
|
context.mock_alembic_history = p4.start()
|
|
|
|
context.add_cleanup(p1.stop)
|
|
context.add_cleanup(p2.stop)
|
|
context.add_cleanup(p3.stop)
|
|
context.add_cleanup(p4.stop)
|
|
|
|
|
|
@given("format_output is mocked")
|
|
def step_mock_format_output(context):
|
|
context.mock_format_output = MagicMock(return_value="<formatted>")
|
|
p = patch.object(db_module, "format_output", context.mock_format_output)
|
|
p.start()
|
|
context.add_cleanup(p.stop)
|
|
|
|
|
|
@given("alembic ScriptDirectory is mocked with sample revisions")
|
|
def step_mock_script_directory(context):
|
|
rev1 = SimpleNamespace(revision="rev001", down_revision=None, doc="Initial schema")
|
|
rev2 = SimpleNamespace(revision="rev002", down_revision="rev001", doc="Add users")
|
|
rev3 = SimpleNamespace(revision="rev003", down_revision="rev002", doc="")
|
|
|
|
mock_script = MagicMock()
|
|
mock_script.walk_revisions.return_value = [rev3, rev2, rev1]
|
|
|
|
mock_cls = MagicMock()
|
|
mock_cls.from_config.return_value = mock_script
|
|
context.mock_script_directory = mock_cls
|
|
|
|
p = patch.object(alembic.script, "ScriptDirectory", mock_cls)
|
|
p.start()
|
|
context.add_cleanup(p.stop)
|
|
|
|
|
|
@given('the db command parameters are revision "{revision}" and format "{fmt}"')
|
|
def step_set_db_params(context, revision, fmt):
|
|
context.db_revision = revision
|
|
context.db_fmt = fmt
|
|
|
|
|
|
@given('the db command format is "{fmt}"')
|
|
def step_set_db_format(context, fmt):
|
|
context.db_fmt = fmt
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# When steps
|
|
# ---------------------------------------------------------------------------
|
|
@when('I invoke the db migrate command with message "{message}"')
|
|
def step_invoke_migrate_with_message(context, message):
|
|
migrate(message=message, fmt="rich")
|
|
|
|
|
|
@when("I invoke the db migrate command with default message")
|
|
def step_invoke_migrate_default(context):
|
|
migrate(fmt="rich")
|
|
|
|
|
|
@when("I invoke the db upgrade command with stored params")
|
|
def step_invoke_upgrade_stored(context):
|
|
upgrade(revision=context.db_revision, fmt=context.db_fmt)
|
|
|
|
|
|
@when("I invoke the db downgrade command with stored params")
|
|
def step_invoke_downgrade_stored(context):
|
|
downgrade(revision=context.db_revision, fmt=context.db_fmt)
|
|
|
|
|
|
@when("I invoke the db current command in rich format")
|
|
def step_invoke_current_rich(context):
|
|
current(fmt="rich")
|
|
|
|
|
|
@when("I invoke the db current command with stored format")
|
|
def step_invoke_current_stored(context):
|
|
current(fmt=context.db_fmt)
|
|
|
|
|
|
@when("I invoke the db history command in rich format")
|
|
def step_invoke_history_rich(context):
|
|
history(fmt="rich")
|
|
|
|
|
|
@when("I invoke the db history command with stored format")
|
|
def step_invoke_history_stored(context):
|
|
history(fmt=context.db_fmt)
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Then steps
|
|
# ---------------------------------------------------------------------------
|
|
@then(
|
|
'alembic revision should have been called with message "{message}" and autogenerate True'
|
|
)
|
|
def step_verify_alembic_revision(context, message):
|
|
context.mock_alembic_revision.assert_called_once_with(
|
|
context.mock_runner.alembic_cfg,
|
|
message=message,
|
|
autogenerate=True,
|
|
)
|
|
|
|
|
|
@then('alembic upgrade should have been called with revision "{revision}"')
|
|
def step_verify_alembic_upgrade(context, revision):
|
|
context.mock_alembic_upgrade.assert_called_once_with(
|
|
context.mock_runner.alembic_cfg,
|
|
revision,
|
|
)
|
|
|
|
|
|
@then("the runner init_or_upgrade should have been called")
|
|
def step_verify_init_or_upgrade(context):
|
|
context.mock_runner.init_or_upgrade.assert_called_once()
|
|
|
|
|
|
@then("the runner get_current_revision should have been called")
|
|
def step_verify_get_current_revision(context):
|
|
context.mock_runner.get_current_revision.assert_called()
|
|
|
|
|
|
@then('alembic downgrade should have been called with revision "{revision}"')
|
|
def step_verify_alembic_downgrade(context, revision):
|
|
context.mock_alembic_downgrade.assert_called_once_with(
|
|
context.mock_runner.alembic_cfg,
|
|
revision,
|
|
)
|
|
|
|
|
|
@then("alembic history should have been called with the runner config")
|
|
def step_verify_alembic_history(context):
|
|
context.mock_alembic_history.assert_called_once_with(
|
|
context.mock_runner.alembic_cfg,
|
|
)
|
|
|
|
|
|
@then('typer should echo a db message containing "{substring}"')
|
|
def step_verify_echo_contains(context, substring):
|
|
assert any(substring in str(msg) for msg in context.echo_calls), (
|
|
f"Expected echo containing '{substring}', got: {context.echo_calls}"
|
|
)
|
|
|
|
|
|
@then("format_output should have been called with status ok data")
|
|
def step_verify_format_output_status_ok(context):
|
|
context.mock_format_output.assert_called_once()
|
|
data = context.mock_format_output.call_args[0][0]
|
|
assert data["status"] == "ok", f"Expected status 'ok', got {data}"
|
|
assert "current_revision" in data
|
|
|
|
|
|
@then("the formatted output should have been echoed")
|
|
def step_verify_formatted_echoed(context):
|
|
assert "<formatted>" in context.echo_calls, (
|
|
f"Expected '<formatted>' in echo calls, got: {context.echo_calls}"
|
|
)
|
|
|
|
|
|
@then("format_output should have been called with current revision data")
|
|
def step_verify_format_output_current(context):
|
|
context.mock_format_output.assert_called_once()
|
|
data = context.mock_format_output.call_args[0][0]
|
|
assert "current_revision" in data
|
|
assert "pending_count" in data
|
|
assert "pending_revisions" in data
|
|
|
|
|
|
@then("format_output should have been called with revision list data")
|
|
def step_verify_format_output_revisions(context):
|
|
context.mock_format_output.assert_called_once()
|
|
data = context.mock_format_output.call_args[0][0]
|
|
assert isinstance(data, list), f"Expected list, got {type(data)}"
|
|
assert len(data) == 3
|
|
assert data[0]["revision"] == "rev003"
|
|
assert data[1]["revision"] == "rev002"
|
|
assert data[2]["revision"] == "rev001"
|
|
for item in data:
|
|
assert "revision" in item
|
|
assert "down_revision" in item
|
|
assert "description" in item
|