Files
FabledScribe/tests/test_routes_db_maintenance.py
T
bvandeusen c4553d937c
CI & Build / Python lint (push) Successful in 3s
CI & Build / TypeScript typecheck (push) Successful in 33s
CI & Build / Python tests (push) Successful in 48s
CI & Build / Build & push image (push) Successful in 54s
feat(db): scheduled DB maintenance — daily targeted VACUUM (ANALYZE)
Adds a daily off-hours VACUUM (ANALYZE) over the high-churn tables the
retention/purge sweeps churn (app_logs, notifications, token tables, notes,
note_versions), on top of Postgres autovacuum, to reclaim bloat left by the
nightly bulk DELETEs and keep planner stats fresh.

- services/db_maintenance.py: run_maintenance() over a closed table allowlist
  via an AUTOCOMMIT connection (VACUUM can't run in a txn); per-table summary
  persisted as the db_maintenance_last_run admin setting.
- services/db_maintenance_scheduler.py: BackgroundScheduler cron (default
  04:00 UTC, after the 03:30 trash purge); enabled-gate checked at fire time;
  live reschedule on hour change. Wired into app.py start/stop.
- routes/admin.py: admin-only GET/PUT /api/admin/db-maintenance + POST /run.
- settings.py: set_admin_setting() (write-side of get_admin_setting) for
  out-of-request writes.
- SettingsView.vue: admin 'Database maintenance' card — enable toggle, run-hour
  (UTC), Run-now, last-run summary.
- Tests: allowlist is closed, VACUUM issued per table, one failure doesn't
  abort the rest, summary persisted; route/scheduler/service surface.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-14 16:42:04 -04:00

44 lines
1.5 KiB
Python

"""Structural tests for the DB-maintenance admin routes + scheduler surface."""
def test_admin_handlers_callable():
from scribe.routes import admin as admin_routes
for name in ("get_db_maintenance", "update_db_maintenance", "run_db_maintenance_now"):
assert callable(getattr(admin_routes, name))
def test_db_maintenance_routes_registered():
from scribe.app import create_app
app = create_app()
rules = {r.rule for r in app.url_map.iter_rules()}
assert "/api/admin/db-maintenance" in rules
assert "/api/admin/db-maintenance/run" in rules
def test_scheduler_surface():
from scribe.services import db_maintenance_scheduler as sched
for fn in (
"start_db_maintenance_scheduler",
"stop_db_maintenance_scheduler",
"reschedule_db_maintenance",
"get_maintenance_hour",
"is_maintenance_enabled",
):
assert callable(getattr(sched, fn)), f"scheduler missing {fn}"
def test_service_surface_and_allowlist():
from scribe.services.db_maintenance import MAINTENANCE_TABLES, get_last_run, run_maintenance
assert callable(run_maintenance) and callable(get_last_run)
# The allowlist is a closed tuple covering exactly the high-churn tables.
assert isinstance(MAINTENANCE_TABLES, tuple)
assert set(MAINTENANCE_TABLES) == {
"app_logs", "notifications", "password_reset_tokens",
"invitation_tokens", "notes", "note_versions",
}
def test_set_admin_setting_exists():
from scribe.services.settings import set_admin_setting
assert callable(set_admin_setting)