feat(harness): manifest archived/group fields + session mutation helpers
This commit is contained in:
@@ -0,0 +1,69 @@
|
|||||||
|
"""Tests for session manifest mutations (rename, group, archive, delete)."""
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
from tht.config import DatabaseConfig
|
||||||
|
from tht.session.store import (
|
||||||
|
SessionError,
|
||||||
|
create_session,
|
||||||
|
delete_session,
|
||||||
|
load_session,
|
||||||
|
set_archived,
|
||||||
|
set_group,
|
||||||
|
set_name,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def _db():
|
||||||
|
return DatabaseConfig(
|
||||||
|
database="testdb", user="u", password="p", # noqa: S106
|
||||||
|
**{"schema": "public"},
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_manifest_defaults(tmp_path):
|
||||||
|
m = create_session("domanda", _db(), tmp_path)
|
||||||
|
assert m.archived is False
|
||||||
|
assert m.group is None
|
||||||
|
assert m.name is None
|
||||||
|
|
||||||
|
|
||||||
|
def test_set_name(tmp_path):
|
||||||
|
m = create_session("domanda", _db(), tmp_path)
|
||||||
|
set_name(m.id, "Pazienti 2024", tmp_path)
|
||||||
|
assert load_session(m.id, tmp_path).name == "Pazienti 2024"
|
||||||
|
|
||||||
|
|
||||||
|
def test_set_name_empty_clears(tmp_path):
|
||||||
|
m = create_session("domanda", _db(), tmp_path)
|
||||||
|
set_name(m.id, "x", tmp_path)
|
||||||
|
set_name(m.id, "", tmp_path)
|
||||||
|
assert load_session(m.id, tmp_path).name is None
|
||||||
|
|
||||||
|
|
||||||
|
def test_set_group_and_clear(tmp_path):
|
||||||
|
m = create_session("domanda", _db(), tmp_path)
|
||||||
|
set_group(m.id, "Aritmologia", tmp_path)
|
||||||
|
assert load_session(m.id, tmp_path).group == "Aritmologia"
|
||||||
|
set_group(m.id, "", tmp_path)
|
||||||
|
assert load_session(m.id, tmp_path).group is None
|
||||||
|
|
||||||
|
|
||||||
|
def test_set_archived(tmp_path):
|
||||||
|
m = create_session("domanda", _db(), tmp_path)
|
||||||
|
set_archived(m.id, True, tmp_path)
|
||||||
|
assert load_session(m.id, tmp_path).archived is True
|
||||||
|
set_archived(m.id, False, tmp_path)
|
||||||
|
assert load_session(m.id, tmp_path).archived is False
|
||||||
|
|
||||||
|
|
||||||
|
def test_delete_session(tmp_path):
|
||||||
|
m = create_session("domanda", _db(), tmp_path)
|
||||||
|
delete_session(m.id, tmp_path)
|
||||||
|
assert not (tmp_path / m.id).exists()
|
||||||
|
with pytest.raises(SessionError):
|
||||||
|
load_session(m.id, tmp_path)
|
||||||
|
|
||||||
|
|
||||||
|
def test_delete_missing_raises(tmp_path):
|
||||||
|
with pytest.raises(SessionError):
|
||||||
|
delete_session("nope", tmp_path)
|
||||||
@@ -44,6 +44,9 @@ def _list_sessions(sessions_root: Path) -> list[dict]:
|
|||||||
"created_at": m.created_at.isoformat(),
|
"created_at": m.created_at.isoformat(),
|
||||||
"updated_at": m.updated_at.isoformat() if m.updated_at else None,
|
"updated_at": m.updated_at.isoformat() if m.updated_at else None,
|
||||||
"author": m.author,
|
"author": m.author,
|
||||||
|
"name": m.name,
|
||||||
|
"group": m.group,
|
||||||
|
"archived": m.archived,
|
||||||
})
|
})
|
||||||
out.sort(key=lambda r: r["created_at"], reverse=True)
|
out.sort(key=lambda r: r["created_at"], reverse=True)
|
||||||
return out
|
return out
|
||||||
|
|||||||
@@ -43,6 +43,8 @@ class SessionManifest(_YamlModel):
|
|||||||
model: str | None = None
|
model: str | None = None
|
||||||
thinking: str | None = None
|
thinking: str | None = None
|
||||||
name: str | None = None
|
name: str | None = None
|
||||||
|
archived: bool = False
|
||||||
|
group: str | None = None
|
||||||
|
|
||||||
|
|
||||||
class Candidate(BaseModel):
|
class Candidate(BaseModel):
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import os
|
import os
|
||||||
|
import shutil
|
||||||
from datetime import UTC, datetime
|
from datetime import UTC, datetime
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
@@ -127,3 +128,39 @@ def close_session(session_id: str, sessions_root: Path) -> SessionManifest:
|
|||||||
manifest.updated_by = current_author()
|
manifest.updated_by = current_author()
|
||||||
manifest.to_yaml(sessions_root / session_id / MANIFEST)
|
manifest.to_yaml(sessions_root / session_id / MANIFEST)
|
||||||
return manifest
|
return manifest
|
||||||
|
|
||||||
|
|
||||||
|
def _save_touched(manifest: SessionManifest, sessions_root: Path) -> SessionManifest:
|
||||||
|
"""Persist `manifest` updating updated_at/updated_by (single save path for mutations)."""
|
||||||
|
manifest.updated_at = datetime.now(UTC)
|
||||||
|
manifest.updated_by = current_author()
|
||||||
|
manifest.to_yaml(sessions_root / manifest.id / MANIFEST)
|
||||||
|
return manifest
|
||||||
|
|
||||||
|
|
||||||
|
def set_name(session_id: str, name: str | None, sessions_root: Path) -> SessionManifest:
|
||||||
|
"""Set the descriptive name (empty/blank clears it back to None)."""
|
||||||
|
manifest = load_session(session_id, sessions_root)
|
||||||
|
manifest.name = (name or "").strip() or None
|
||||||
|
return _save_touched(manifest, sessions_root)
|
||||||
|
|
||||||
|
|
||||||
|
def set_group(session_id: str, group: str | None, sessions_root: Path) -> SessionManifest:
|
||||||
|
"""Set the group (empty/blank clears it back to None)."""
|
||||||
|
manifest = load_session(session_id, sessions_root)
|
||||||
|
manifest.group = (group or "").strip() or None
|
||||||
|
return _save_touched(manifest, sessions_root)
|
||||||
|
|
||||||
|
|
||||||
|
def set_archived(session_id: str, archived: bool, sessions_root: Path) -> SessionManifest:
|
||||||
|
"""Flip the archived flag. Archiving does NOT change resumability (a finalized
|
||||||
|
session stays read-only); unarchive only moves it back to the active list."""
|
||||||
|
manifest = load_session(session_id, sessions_root)
|
||||||
|
manifest.archived = archived
|
||||||
|
return _save_touched(manifest, sessions_root)
|
||||||
|
|
||||||
|
|
||||||
|
def delete_session(session_id: str, sessions_root: Path) -> None:
|
||||||
|
"""Hard-delete the session directory. SessionError if it does not exist."""
|
||||||
|
load_session(session_id, sessions_root) # raises SessionError if absent
|
||||||
|
shutil.rmtree(sessions_root / session_id)
|
||||||
|
|||||||
Reference in New Issue
Block a user