test(tui): add TDD failing test for SQLite session persistence

Add BDD scenarios that capture bug #4739 — the missing TUI SQLite
session persistence layer. The cleveragents.tui.session_store module
and TuiSessionStore class do not exist; these tests verify their
absence and will pass once the implementation is in place.

All scenarios are tagged @tdd_expected_fail so CI passes while the
module is absent. The expected-fail mechanism inverts the result:
a failing AssertionError means the bug still exists (CI passes).

ISSUES CLOSED: #10879
This commit is contained in:
2026-04-28 07:09:44 +00:00
committed by Forgejo
parent 036099a68a
commit f5add6ffa3
2 changed files with 193 additions and 0 deletions
@@ -0,0 +1,154 @@
"""Step definitions for TDD Bug #4739 — TUI SQLite session persistence not implemented.
These steps verify that ``cleveragents.tui.session_store`` exists and that
``TuiSessionStore`` can persist and retrieve session records from SQLite.
All scenarios are tagged ``@tdd_expected_fail`` so CI passes while the
module is absent. The expected-fail mechanism inverts the result: a
failing assertion means the bug is still present (CI passes); a passing
assertion means the fix has been applied (CI also passes after the
``@tdd_expected_fail`` tag is removed in the bugfix PR).
Failure mode: ``AssertionError`` (not ``ImportError`` or ``RuntimeError``).
"""
from __future__ import annotations
import importlib
import os
import shutil
import tempfile
import types
from behave import given, then, when
from behave.runner import Context
@given("the tdd4739 test environment is set up")
def step_tdd4739_setup(context: Context) -> None:
"""Initialise context attributes used across tdd4739 steps."""
context.tdd4739_module: types.ModuleType | None = None
context.tdd4739_import_error: Exception | None = None
context.tdd4739_store: object | None = None
context.tdd4739_tmpdir: str | None = None
@given("the tdd4739 test environment is set up with a temp db path")
def step_tdd4739_setup_with_tmpdir(context: Context) -> None:
"""Initialise context and create a temporary directory for the SQLite db."""
context.tdd4739_module = None
context.tdd4739_import_error = None
context.tdd4739_store = None
tmpdir = tempfile.mkdtemp(prefix="tdd4739_")
context.tdd4739_tmpdir = tmpdir
context.tdd4739_db_path = os.path.join(tmpdir, "tui.db")
def _cleanup() -> None:
shutil.rmtree(tmpdir, ignore_errors=True)
context.add_cleanup(_cleanup)
@when("I attempt to import cleveragents.tui.session_store")
def step_tdd4739_import(context: Context) -> None:
"""Attempt to import the session_store module; capture any ImportError."""
try:
mod = importlib.import_module("cleveragents.tui.session_store")
context.tdd4739_module = mod
context.tdd4739_import_error = None
except ImportError as exc:
context.tdd4739_module = None
context.tdd4739_import_error = exc
@then("the tdd4739 import should succeed without errors")
def step_tdd4739_import_ok(context: Context) -> None:
"""Assert the import succeeded — fails via AssertionError if module is absent."""
assert context.tdd4739_import_error is None, (
f"cleveragents.tui.session_store could not be imported: "
f"{context.tdd4739_import_error}"
)
assert context.tdd4739_module is not None, (
"cleveragents.tui.session_store module is None after import"
)
@then("the tdd4739 module should expose a TuiSessionStore class")
def step_tdd4739_class_exists(context: Context) -> None:
"""Assert TuiSessionStore is present in the module."""
assert context.tdd4739_import_error is None, (
f"cleveragents.tui.session_store could not be imported: "
f"{context.tdd4739_import_error}"
)
mod = context.tdd4739_module
assert mod is not None, "session_store module is None"
assert hasattr(mod, "TuiSessionStore"), (
"cleveragents.tui.session_store does not expose a TuiSessionStore class"
)
@when("I create a TuiSessionStore pointing at the temp db path")
def step_tdd4739_create_store(context: Context) -> None:
"""Instantiate TuiSessionStore with the temp db path."""
try:
mod = importlib.import_module("cleveragents.tui.session_store")
except ImportError as exc:
raise AssertionError(
f"cleveragents.tui.session_store could not be imported: {exc}"
) from exc
assert hasattr(mod, "TuiSessionStore"), (
"cleveragents.tui.session_store does not expose a TuiSessionStore class"
)
context.tdd4739_store = mod.TuiSessionStore(db_path=context.tdd4739_db_path)
@when('I save a tdd4739 session record with id "{session_id}"')
def step_tdd4739_save_session(context: Context, session_id: str) -> None:
"""Save a minimal session record to the store."""
store = context.tdd4739_store
assert store is not None, "TuiSessionStore was not created"
store.save( # type: ignore[union-attr]
session_id=session_id,
persona_name="default",
actor_identity="anthropic/claude-4-sonnet",
title=f"Test session {session_id}",
prompt_count=0,
total_cost=0.0,
created_at="2026-01-01T00:00:00Z",
last_used="2026-01-01T00:00:00Z",
project_path=None,
meta_json="{}",
)
@then('the tdd4739 session record should be retrievable by id "{session_id}"')
def step_tdd4739_get_session(context: Context, session_id: str) -> None:
"""Assert the session record can be retrieved by its id."""
store = context.tdd4739_store
assert store is not None, "TuiSessionStore was not created"
record = store.get(session_id) # type: ignore[union-attr]
assert record is not None, (
f"TuiSessionStore.get('{session_id}') returned None — "
f"session was not persisted"
)
assert getattr(record, "id", None) == session_id or (
isinstance(record, dict) and record.get("id") == session_id
), (
f"Retrieved record id mismatch: expected '{session_id}', "
f"got {getattr(record, 'id', record)!r}"
)
@then("the tdd4739 session store should list {count:d} sessions")
def step_tdd4739_list_sessions(context: Context, count: int) -> None:
"""Assert the store lists the expected number of sessions."""
store = context.tdd4739_store
assert store is not None, "TuiSessionStore was not created"
sessions = store.list_all() # type: ignore[union-attr]
assert sessions is not None, "TuiSessionStore.list_all() returned None"
actual = len(sessions)
assert actual == count, (
f"Expected {count} sessions in store, got {actual}"
)
@@ -0,0 +1,39 @@
@tdd_issue @tdd_issue_4739
Feature: Bug #4739 — TUI SQLite session persistence not implemented
As a developer
I want to verify that the TUI session persistence layer exists
So that the bug is captured and will be caught by a regression test
The spec (§Session Persistence and Resume) requires TUI sessions to be
persisted in an SQLite database at ~/.local/state/cleveragents/tui.db
via a TuiSessionStore class in cleveragents.tui.session_store.
Currently no such module exists the TUI hardcodes a single in-memory
session and has no SQLite persistence layer.
@tdd_issue @tdd_issue_4739 @tdd_expected_fail
Scenario: TuiSessionStore module can be imported from cleveragents.tui
Given the tdd4739 test environment is set up
When I attempt to import cleveragents.tui.session_store
Then the tdd4739 import should succeed without errors
@tdd_issue @tdd_issue_4739 @tdd_expected_fail
Scenario: TuiSessionStore class exists in the session_store module
Given the tdd4739 test environment is set up
When I attempt to import cleveragents.tui.session_store
Then the tdd4739 module should expose a TuiSessionStore class
@tdd_issue @tdd_issue_4739 @tdd_expected_fail
Scenario: TuiSessionStore can persist a session record to SQLite
Given the tdd4739 test environment is set up with a temp db path
When I create a TuiSessionStore pointing at the temp db path
And I save a tdd4739 session record with id "test-session-001"
Then the tdd4739 session record should be retrievable by id "test-session-001"
@tdd_issue @tdd_issue_4739 @tdd_expected_fail
Scenario: TuiSessionStore lists all persisted sessions
Given the tdd4739 test environment is set up with a temp db path
When I create a TuiSessionStore pointing at the temp db path
And I save a tdd4739 session record with id "sess-a"
And I save a tdd4739 session record with id "sess-b"
Then the tdd4739 session store should list 2 sessions