Stand up the full SQLite content layer: all 7 tables from the authoritative schema with WAL + foreign-keys enforced per-connection, entity dataclasses plus row mappers, hand-rolled versioned migrations tracked in schema_migrations, and an idempotent Python seed (system user + welcome post + About page). Add a Markdown->HTML service using markdown-it-py with a strict bleach allowlist (tables intentionally omitted on both sides). Add a typed in-process TTLCache[K,V] and wire it into real DB-backed PostService and PageService, both exposing invalidate_all() for Phase 4 admin writes. Rewire / and /about to read from the DB; homepage renders the seeded welcome post, About renders page.title + sanitized body_html_cached. Update the Phase 1 route tests accordingly. Mark Phase 2 complete in docs/ROADMAP.md.
54 lines
1.8 KiB
Python
54 lines
1.8 KiB
Python
"""Tests for :class:`app.services.pages.PageService`.
|
|
|
|
Uses the session-scoped seeded ``db_engine`` fixture.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from sqlalchemy import Engine
|
|
|
|
from app.models.entities import Page
|
|
from app.services.pages import PageService
|
|
|
|
|
|
def test_get_by_slug_returns_seeded_about_page(db_engine: Engine) -> None:
|
|
"""The seeded About page loads as a :class:`Page` dataclass."""
|
|
service = PageService(db_engine)
|
|
page = service.get_by_slug("about")
|
|
|
|
assert page is not None
|
|
assert isinstance(page, Page)
|
|
assert page.slug == "about"
|
|
assert page.title == "About the Farm"
|
|
# The sanitized HTML must contain a <p> since the seed Markdown
|
|
# has multiple paragraphs; this also proves the Markdown pipeline
|
|
# ran at seed time.
|
|
assert "<p>" in page.body_html_cached
|
|
assert page.published is True
|
|
|
|
|
|
def test_get_by_slug_returns_none_for_unknown_slug(db_engine: Engine) -> None:
|
|
"""Unknown slugs return ``None`` rather than raising."""
|
|
service = PageService(db_engine)
|
|
assert service.get_by_slug("does-not-exist") is None
|
|
|
|
|
|
def test_get_by_slug_is_cached(db_engine: Engine) -> None:
|
|
"""The TTL cache wraps page lookups keyed by slug."""
|
|
service = PageService(db_engine)
|
|
first = service.get_by_slug("about")
|
|
second = service.get_by_slug("about")
|
|
assert first is second
|
|
|
|
|
|
def test_invalidate_all_forces_reload(db_engine: Engine) -> None:
|
|
"""After :meth:`invalidate_all` the next call re-hits the DB."""
|
|
service = PageService(db_engine)
|
|
first = service.get_by_slug("about")
|
|
service.invalidate_all()
|
|
second = service.get_by_slug("about")
|
|
assert first is not second
|
|
# Same slug, same row — content equal, identity different.
|
|
assert first is not None and second is not None
|
|
assert first.slug == second.slug == "about"
|