forked from HAL9000/cleveragents-core
a808c395f9
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
205 lines
7.0 KiB
Python
205 lines
7.0 KiB
Python
"""Step definitions for PostgreSQLAnalyzer coverage-boost scenarios.
|
|
|
|
Targets uncovered lines in postgresql_analyzer.py:
|
|
- Lines 112-116: exception handler in analyze()
|
|
- Line 135: duplicate CREATE SCHEMA deduplication
|
|
- Line 198: _extract_tables with tables_seen=None
|
|
- Line 285: CREATE VIEW without trailing semicolon
|
|
- Lines 297-302: schema-qualified CREATE VIEW with uko:contains
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from unittest.mock import patch
|
|
|
|
from behave import given, then, use_step_matcher, when
|
|
from behave.runner import Context
|
|
|
|
use_step_matcher("re")
|
|
|
|
from cleveragents.domain.models.acms.postgresql_analyzer import ( # noqa: E402
|
|
PostgreSQLAnalyzer,
|
|
)
|
|
|
|
__all__: list[str] = []
|
|
|
|
_SAMPLE_URI = "uko://test/coverage-boost"
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Given
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
@given(r"a fresh PostgreSQLAnalyzer instance")
|
|
def step_given_fresh_postgresql_analyzer(context: Context) -> None:
|
|
context.analyzer = PostgreSQLAnalyzer()
|
|
context.triples = []
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# When
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
@when(r"I analyze DDL with duplicate schemas:")
|
|
def step_when_analyze_ddl_duplicate_schemas(context: Context) -> None:
|
|
context.triples = context.analyzer.analyze(context.text, _SAMPLE_URI)
|
|
|
|
|
|
@when(r"I analyze DDL that triggers an internal parse error")
|
|
def step_when_analyze_ddl_with_parse_error(context: Context) -> None:
|
|
"""Force an exception inside _extract_tables to exercise lines 112-116."""
|
|
with (
|
|
patch.object(
|
|
context.analyzer,
|
|
"_extract_tables",
|
|
side_effect=RuntimeError("simulated parse failure"),
|
|
),
|
|
# Capture the log output to verify the warning was emitted.
|
|
patch(
|
|
"cleveragents.domain.models.acms.postgresql_analyzer.logger"
|
|
) as mock_logger,
|
|
):
|
|
context.triples = context.analyzer.analyze(
|
|
"CREATE SCHEMA testschema;\nCREATE TABLE t (id INT);\n",
|
|
_SAMPLE_URI,
|
|
)
|
|
context.mock_logger = mock_logger
|
|
|
|
|
|
@when(r"I call _extract_tables directly without tables_seen on:")
|
|
def step_when_call_extract_tables_directly(context: Context) -> None:
|
|
"""Call _extract_tables with tables_seen=None to hit line 198."""
|
|
context.triples = context.analyzer._extract_tables(
|
|
context.text,
|
|
_SAMPLE_URI,
|
|
set(),
|
|
None,
|
|
)
|
|
|
|
|
|
@when(r"I analyze DDL with a view missing its semicolon:")
|
|
def step_when_analyze_ddl_view_no_semicolon(context: Context) -> None:
|
|
context.triples = context.analyzer.analyze(context.text, _SAMPLE_URI)
|
|
|
|
|
|
@when(r"I analyze DDL with a schema-qualified view:")
|
|
def step_when_analyze_ddl_schema_qualified_view(context: Context) -> None:
|
|
context.triples = context.analyzer.analyze(context.text, _SAMPLE_URI)
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Then
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
@then(r"exactly (?P<count>\d+) Schema type triple should exist")
|
|
def step_then_exactly_n_schema_triples(context: Context, count: str) -> None:
|
|
count_int = int(count)
|
|
actual = sum(
|
|
1
|
|
for t in context.triples
|
|
if t.predicate == "rdf:type" and t.object_uri == "uko-data:Schema"
|
|
)
|
|
assert actual == count_int, (
|
|
f"Expected {count_int} Schema type triple(s), got {actual}.\n"
|
|
f"Triples: {context.triples}"
|
|
)
|
|
|
|
|
|
@then(
|
|
r'the result triples should contain predicate "(?P<pred>[^"]+)" with value "(?P<val>[^"]+)"'
|
|
)
|
|
def step_then_result_contains_pred_value(context: Context, pred: str, val: str) -> None:
|
|
found = any(t.predicate == pred and t.object_value == val for t in context.triples)
|
|
assert found, (
|
|
f"No triple with predicate={pred!r} object_value={val!r}.\n"
|
|
f"Triples: {context.triples}"
|
|
)
|
|
|
|
|
|
@then(
|
|
r'the result triples should contain predicate "(?P<pred>[^"]+)" with uri "(?P<uri>[^"]+)"'
|
|
)
|
|
def step_then_result_contains_pred_uri(context: Context, pred: str, uri: str) -> None:
|
|
found = any(t.predicate == pred and t.object_uri == uri for t in context.triples)
|
|
assert found, (
|
|
f"No triple with predicate={pred!r} object_uri={uri!r}.\n"
|
|
f"Triples: {context.triples}"
|
|
)
|
|
|
|
|
|
@then(r'the result triples should contain predicate "(?P<pred>[^"]+)" present')
|
|
def step_then_result_contains_pred(context: Context, pred: str) -> None:
|
|
found = any(t.predicate == pred for t in context.triples)
|
|
assert found, f"No triple with predicate={pred!r}.\nTriples: {context.triples}"
|
|
|
|
|
|
@then(r"the partial results should be returned without raising")
|
|
def step_then_partial_results_returned(context: Context) -> None:
|
|
# analyze() should have caught the exception and returned a list
|
|
assert isinstance(context.triples, list), (
|
|
f"Expected a list, got {type(context.triples).__name__}"
|
|
)
|
|
|
|
|
|
@then(r"the parse error should have been logged as a warning")
|
|
def step_then_parse_error_logged(context: Context) -> None:
|
|
mock_logger = context.mock_logger
|
|
mock_logger.warning.assert_called_once()
|
|
call_args = mock_logger.warning.call_args
|
|
assert "parse error" in call_args[0][0].lower(), (
|
|
f"Expected 'parse error' in warning message, got: {call_args[0][0]!r}"
|
|
)
|
|
|
|
|
|
@then(r'the direct extraction should produce Table triples for "(?P<table_name>[^"]+)"')
|
|
def step_then_direct_extraction_produces_table(
|
|
context: Context, table_name: str
|
|
) -> None:
|
|
has_table_type = any(
|
|
t.predicate == "rdf:type" and t.object_uri == "uko-data:Table"
|
|
for t in context.triples
|
|
)
|
|
has_label = any(
|
|
t.predicate == "rdfs:label" and t.object_value == table_name
|
|
for t in context.triples
|
|
)
|
|
assert has_table_type, (
|
|
f"No rdf:type uko-data:Table triple found.\nTriples: {context.triples}"
|
|
)
|
|
assert has_label, (
|
|
f"No rdfs:label={table_name!r} triple found.\nTriples: {context.triples}"
|
|
)
|
|
|
|
|
|
@then(r'the viewDefinition value should contain "(?P<fragment>[^"]+)"')
|
|
def step_then_view_definition_contains(context: Context, fragment: str) -> None:
|
|
found = any(
|
|
t.predicate == "uko-data:viewDefinition" and fragment in t.object_value
|
|
for t in context.triples
|
|
)
|
|
assert found, (
|
|
f"No uko-data:viewDefinition triple containing {fragment!r}.\n"
|
|
f"Triples: {context.triples}"
|
|
)
|
|
|
|
|
|
@then(
|
|
r'the result triples should contain predicate "(?P<pred>[^"]+)" '
|
|
r'linking schema "(?P<schema>[^"]+)" to view "(?P<view>[^"]+)"'
|
|
)
|
|
def step_then_result_contains_schema_view_link(
|
|
context: Context, pred: str, schema: str, view: str
|
|
) -> None:
|
|
found = any(
|
|
t.predicate == pred and schema in t.subject_uri and view in t.object_uri
|
|
for t in context.triples
|
|
)
|
|
assert found, (
|
|
f"No triple with predicate={pred!r} linking schema containing "
|
|
f"{schema!r} to view containing {view!r}.\n"
|
|
f"Triples: {context.triples}"
|
|
)
|