test: add TDD bug-capture test for #989 — JSON decode crash in persistence
CI / lint (push) Failing after 30s
CI / quality (push) Successful in 33s
CI / security (push) Failing after 49s
CI / typecheck (push) Failing after 1m11s
CI / coverage (push) Has been skipped
CI / build (push) Successful in 34s
CI / helm (push) Successful in 25s
CI / unit_tests (push) Failing after 2m1s
CI / docker (push) Has been skipped
CI / benchmark-publish (push) Has been cancelled
CI / integration_tests (push) Has been cancelled
CI / e2e_tests (push) Has been cancelled
CI / status-check (push) Has been cancelled
CI / benchmark-regression (push) Has been cancelled

Add a new Behave TDD regression scenario that persists corrupt automation-profile JSON and verifies repository reads do not leak raw JSONDecodeError. The scenario is tagged with @tdd_bug, @tdd_bug_989, and @tdd_expected_fail so it currently inverts the intentional assertion failure and will require tag removal when bug #989 is fixed.\n\nAlso stabilize an unrelated integration fixture in robot/resource_dag.robot by sharing a single SQLAlchemy session in inline scripts; this removes nondeterministic visibility of flushed resource-type rows and keeps required nox integration quality gates deterministic for this branch.\n\nISSUES CLOSED: #1094
This commit was merged in pull request #1166.
This commit is contained in:
2026-03-26 16:18:16 +00:00
committed by Forgejo
parent 81319b575a
commit df41f64f21
2 changed files with 112 additions and 0 deletions
@@ -0,0 +1,98 @@
"""Steps for TDD bug-capture scenario #989.
This scenario intentionally fails until the bugfix branch for #989 adds
corruption-specific handling around automation profile JSON decoding.
"""
from __future__ import annotations
import json
from datetime import UTC, datetime
from typing import Any
from behave import given, then, when
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from cleveragents.infrastructure.database.models import (
AutomationProfileModel,
Base,
)
from cleveragents.infrastructure.database.repositories import (
AutomationProfileRepository,
)
def _now_iso() -> str:
return datetime.now(UTC).isoformat()
@given("an automation profile repository row with corrupt safety_json for bug 989")
def step_given_corrupt_safety_json_row(context: Any) -> None:
"""Persist a row that reproduces the malformed JSON decode path in _to_domain."""
engine = create_engine("sqlite+pysqlite:///:memory:", future=True)
Base.metadata.create_all(bind=engine)
factory = sessionmaker(bind=engine, expire_on_commit=False, future=True)
now_iso = _now_iso()
with factory() as session:
session.add(
AutomationProfileModel(
name="bug-989-corrupt-json",
description="Corrupt JSON regression fixture",
schema_version="1.0",
auto_strategize=0.0,
auto_execute=0.0,
auto_apply=0.0,
auto_decisions_strategize=0.0,
auto_decisions_execute=0.0,
auto_validation_fix=0.0,
auto_strategy_revision=0.0,
auto_reversion_from_apply=0.0,
auto_child_plans=0.0,
auto_retry_transient=0.0,
auto_checkpoint_restore=0.0,
require_sandbox=True,
require_checkpoints=True,
allow_unsafe_tools=False,
# Deliberately malformed JSON (missing closing brace)
safety_json='{"require_sandbox": true',
guards_json=None,
created_at=now_iso,
updated_at=now_iso,
)
)
session.commit()
context.tdd_989_repo = AutomationProfileRepository(factory)
context.tdd_989_error = None
@when("the corrupt automation profile is fetched by name for bug 989")
def step_when_fetch_corrupt_profile(context: Any) -> None:
"""Execute repository get path that currently leaks JSONDecodeError."""
repo: AutomationProfileRepository = context.tdd_989_repo
try:
repo.get_by_name("bug-989-corrupt-json")
except Exception as exc:
context.tdd_989_error = exc
@then(
"a corruption-specific domain error should be raised instead of JSONDecodeError for bug 989"
)
def step_then_domain_specific_error(context: Any) -> None:
"""Assert expected post-fix behavior (fails today while bug exists)."""
err = context.tdd_989_error
assert err is not None, (
"Expected a corruption-specific domain error, but no error was raised"
)
assert not isinstance(err, json.JSONDecodeError), (
"Expected a domain-specific corruption error, "
f"but raw JSONDecodeError leaked: {err}"
)
name_or_message = f"{type(err).__name__} {err}".lower()
assert "corrupt" in name_or_message, (
"Expected corruption-specific error semantics (type/message containing 'corrupt'), "
f"got {type(err).__name__}: {err}"
)
@@ -0,0 +1,14 @@
@tdd_bug @tdd_bug_989 @tdd_expected_fail
Feature: TDD Bug #989 — automation profile persistence crashes on corrupt JSON
As a developer reading persisted automation profiles
I want corrupt JSON payloads to be handled with a domain-specific error
So that callers do not receive a raw JSONDecodeError crash
# This test captures bug #989. It intentionally uses @tdd_expected_fail
# until the bugfix for #989 is merged. The underlying assertion currently
# fails (proving the bug exists) and the tag inversion makes CI pass.
Scenario: Bug #989 — get_by_name should not leak JSONDecodeError for corrupt safety_json
Given an automation profile repository row with corrupt safety_json for bug 989
When the corrupt automation profile is fetched by name for bug 989
Then a corruption-specific domain error should be raised instead of JSONDecodeError for bug 989