206 lines
6.0 KiB
Python
206 lines
6.0 KiB
Python
"""Tests for `tht session list --json` and `tht session show --json` (Task 7)."""
|
|
import json
|
|
|
|
import pytest
|
|
from typer.testing import CliRunner
|
|
|
|
from tht.cli.session_cmd import _list_sessions, session_app
|
|
from tht.session.store import create_session
|
|
|
|
|
|
def _make_db():
|
|
from tht.config import DatabaseConfig
|
|
|
|
return DatabaseConfig(
|
|
database="testdb",
|
|
user="testuser",
|
|
password="testpass", # noqa: S106
|
|
**{"schema": "public"},
|
|
)
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Unit: _list_sessions helper
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
def test_list_sessions_returns_all_created(tmp_path):
|
|
db = _make_db()
|
|
m1 = create_session("prima domanda", db, tmp_path)
|
|
m2 = create_session("seconda domanda", db, tmp_path)
|
|
rows = _list_sessions(tmp_path)
|
|
ids = [r["id"] for r in rows]
|
|
assert m1.id in ids
|
|
assert m2.id in ids
|
|
|
|
|
|
def test_list_sessions_required_keys(tmp_path):
|
|
db = _make_db()
|
|
create_session("qualsiasi domanda", db, tmp_path)
|
|
rows = _list_sessions(tmp_path)
|
|
assert len(rows) >= 1
|
|
required = {"id", "status", "question", "summary", "created_at", "updated_at", "author"}
|
|
assert required.issubset(rows[0].keys())
|
|
|
|
|
|
def test_list_sessions_sorted_desc(tmp_path):
|
|
db = _make_db()
|
|
create_session("prima", db, tmp_path)
|
|
create_session("seconda", db, tmp_path)
|
|
rows = _list_sessions(tmp_path)
|
|
dates = [r["created_at"] for r in rows]
|
|
assert dates == sorted(dates, reverse=True)
|
|
|
|
|
|
def test_list_sessions_empty_dir(tmp_path):
|
|
rows = _list_sessions(tmp_path)
|
|
assert rows == []
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# CLI: tht session list --json
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
def test_cli_list_json_valid(tmp_path, monkeypatch):
|
|
db = _make_db()
|
|
m = create_session("test question", db, tmp_path)
|
|
|
|
# Patch _load_config_or_exit so we don't need a real config file
|
|
from tht.cli import session_cmd
|
|
|
|
class FakePaths:
|
|
sessions = tmp_path
|
|
|
|
class FakeCfg:
|
|
paths = FakePaths()
|
|
|
|
monkeypatch.setattr(session_cmd, "_load_config_or_exit", lambda _: FakeCfg())
|
|
|
|
runner = CliRunner()
|
|
result = runner.invoke(session_app, ["list", "--json"])
|
|
assert result.exit_code == 0, result.output
|
|
rows = json.loads(result.output)
|
|
assert isinstance(rows, list)
|
|
ids = [r["id"] for r in rows]
|
|
assert m.id in ids
|
|
|
|
|
|
def test_cli_list_human_no_json_noise(tmp_path, monkeypatch):
|
|
"""Human mode must not emit JSON."""
|
|
db = _make_db()
|
|
create_session("human question", db, tmp_path)
|
|
|
|
from tht.cli import session_cmd
|
|
|
|
class FakePaths:
|
|
sessions = tmp_path
|
|
|
|
class FakeCfg:
|
|
paths = FakePaths()
|
|
|
|
monkeypatch.setattr(session_cmd, "_load_config_or_exit", lambda _: FakeCfg())
|
|
|
|
runner = CliRunner()
|
|
result = runner.invoke(session_app, ["list"])
|
|
assert result.exit_code == 0
|
|
# Must not be parseable as JSON array
|
|
with pytest.raises(json.JSONDecodeError):
|
|
json.loads(result.output)
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# CLI: tht session show --json
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
def test_cli_show_json_valid(tmp_path, monkeypatch):
|
|
db = _make_db()
|
|
m = create_session("domanda show json", db, tmp_path)
|
|
|
|
from tht.cli import session_cmd
|
|
|
|
class FakePaths:
|
|
sessions = tmp_path
|
|
|
|
class FakeCfg:
|
|
paths = FakePaths()
|
|
database = db
|
|
|
|
monkeypatch.setattr(session_cmd, "_load_config_or_exit", lambda _: FakeCfg())
|
|
|
|
runner = CliRunner()
|
|
result = runner.invoke(session_app, ["show", m.id, "--json"])
|
|
assert result.exit_code == 0, result.output
|
|
data = json.loads(result.output)
|
|
assert data["id"] == m.id
|
|
assert "phase" in data
|
|
assert "has_schema_linking" in data
|
|
# Pin by_alias=True: the alias-sensitive field must serialize as "schema", not "db_schema".
|
|
assert "schema" in data
|
|
assert "db_schema" not in data
|
|
|
|
|
|
def test_cli_show_json_stdout_pristine(tmp_path, monkeypatch):
|
|
"""--json must produce only valid JSON on stdout (no ANSI color codes or extra lines)."""
|
|
db = _make_db()
|
|
m = create_session("pristine stdout test", db, tmp_path)
|
|
|
|
from tht.cli import session_cmd
|
|
|
|
class FakePaths:
|
|
sessions = tmp_path
|
|
|
|
class FakeCfg:
|
|
paths = FakePaths()
|
|
database = db
|
|
|
|
monkeypatch.setattr(session_cmd, "_load_config_or_exit", lambda _: FakeCfg())
|
|
|
|
runner = CliRunner()
|
|
result = runner.invoke(session_app, ["show", m.id, "--json"])
|
|
assert result.exit_code == 0, result.output
|
|
# stdout must parse cleanly as JSON
|
|
data = json.loads(result.output)
|
|
assert isinstance(data, dict)
|
|
|
|
|
|
def test_cli_retrieval_pack_emits_persisted_content(tmp_path, monkeypatch):
|
|
db = _make_db()
|
|
manifest = create_session("test question", db, tmp_path)
|
|
expected = "# Retrieval pack\n\ncontenuto già pronto\n"
|
|
(tmp_path / manifest.id / "retrieval_pack.md").write_text(expected)
|
|
|
|
from tht.cli import session_cmd
|
|
|
|
class FakePaths:
|
|
sessions = tmp_path
|
|
|
|
class FakeCfg:
|
|
paths = FakePaths()
|
|
|
|
monkeypatch.setattr(session_cmd, "_load_config_or_exit", lambda _: FakeCfg())
|
|
result = CliRunner().invoke(session_app, ["retrieval-pack", manifest.id])
|
|
|
|
assert result.exit_code == 0, result.output
|
|
assert result.output == expected
|
|
|
|
|
|
def test_cli_retrieval_pack_missing_is_clear_error(tmp_path, monkeypatch):
|
|
db = _make_db()
|
|
manifest = create_session("test question", db, tmp_path)
|
|
|
|
from tht.cli import session_cmd
|
|
|
|
class FakePaths:
|
|
sessions = tmp_path
|
|
|
|
class FakeCfg:
|
|
paths = FakePaths()
|
|
|
|
monkeypatch.setattr(session_cmd, "_load_config_or_exit", lambda _: FakeCfg())
|
|
result = CliRunner().invoke(session_app, ["retrieval-pack", manifest.id])
|
|
|
|
assert result.exit_code == 1
|
|
assert "retrieval pack non disponibile" in result.output
|