Files
espresso_frame/server/tests/test_render_size_invariants.py
T
tfaour 31adc34a19
Build and push server image / test (push) Successful in 1m18s
Build and push server image / build-and-push (push) Successful in 2m12s
Add a real pytest suite, gating the CI build
64 tests covering: auth/setup and the CSRF gate, the "owner adds their
own data, anyone linked can mute it" permission pattern shared across
calendar-select/tasks-source/whiteboard-source, migration correctness
(fresh install, idempotent re-run, expected columns), battery estimate
outlier rejection, calendar_feed's fetch/merge/partial-failure handling,
webdav_client's fetch/list-directory, the whiteboard force-refresh
throttle bypass and browse endpoint, and render-size invariants across
calendar views/orientations.

No DB/HTTP fixtures need Docker, Node, or a real Immich/CalDAV/WebDAV
server -- a fresh temp SQLite file plus a couple of small local HTTP
servers as test doubles cover it all. Table data is wiped and reseeded
between tests rather than relying on SQLAlchemy's transaction-rollback
isolation pattern, which needs a pysqlite event-listener workaround
app/db.py's engine doesn't have and has no reason to gain just for tests.

Wired into .gitea/workflows/server-docker-build.yml as its own job that
build-and-push now depends on, so a failing suite blocks the image push
rather than just running alongside it for show.
2026-07-23 18:51:54 -04:00

68 lines
2.9 KiB
Python

"""Every renderer that produces a device-facing frame must return
exactly EPD_WIDTH*EPD_HEIGHT/2 bytes (the panel's packed 2px/byte
format) -- firmware writes this straight to the display with no length
checking of its own, so a renderer that's off by even one byte is a
silent on-device corruption bug, not a clean error. This is a cheap,
high-value regression guard: pure PIL rendering, no DB/HTTP/Node."""
from __future__ import annotations
import pytest
from app.calendar_render import CALENDAR_VIEWS, render_calendar
from app.image_pipeline import EPD_HEIGHT, EPD_WIDTH, render_placeholder
EXPECTED_BYTES = EPD_WIDTH * EPD_HEIGHT // 2
ORIENTATIONS = ["landscape", "landscape_flipped", "portrait", "portrait_flipped"]
_SAMPLE_EVENTS = [
{
"summary": "Dentist", "start": "2026-08-01T14:00:00+00:00", "end": "2026-08-01T15:00:00+00:00",
"all_day": False, "sources": [{"owner_display_name": "Alice", "color_index": None}],
},
{
"summary": "Team Offsite", "start": "2026-08-03T00:00:00", "end": "2026-08-04T00:00:00",
"all_day": True, "sources": [{"owner_display_name": "Bob", "color_index": 2}],
},
]
@pytest.mark.parametrize("orientation", ORIENTATIONS)
def test_placeholder_render_size(orientation):
data = render_placeholder(["Not configured yet"], orientation=orientation)
assert len(data) == EXPECTED_BYTES
@pytest.mark.parametrize("view", CALENDAR_VIEWS)
def test_calendar_render_size_across_views(view):
data = render_calendar(_SAMPLE_EVENTS, view, browse_offset=0, orientation="landscape",
palette_rgb=None, timezone="UTC")
assert len(data) == EXPECTED_BYTES
@pytest.mark.parametrize("orientation", ORIENTATIONS)
def test_calendar_render_size_across_orientations(orientation):
data = render_calendar(_SAMPLE_EVENTS, "agenda", browse_offset=0, orientation=orientation,
palette_rgb=None, timezone="UTC")
assert len(data) == EXPECTED_BYTES
def test_calendar_render_size_empty_events():
data = render_calendar([], "week", browse_offset=0, orientation="landscape",
palette_rgb=None, timezone="UTC")
assert len(data) == EXPECTED_BYTES
def test_calendar_render_size_with_fetch_summary_and_tasks():
tasks = [{"summary": "Buy milk", "completed": False}, {"summary": "Walk the dog", "completed": True}]
data = render_calendar(_SAMPLE_EVENTS, "week", browse_offset=0, orientation="landscape",
palette_rgb=None, timezone="UTC", fetch_summary="1 of 2 calendars unavailable",
week_days=5, week_layout="vertical", tasks=tasks)
assert len(data) == EXPECTED_BYTES
def test_calendar_render_size_with_week_start_offset():
data = render_calendar(_SAMPLE_EVENTS, "week", browse_offset=0, orientation="landscape",
palette_rgb=None, timezone="UTC", week_days=3, week_start_offset=2)
assert len(data) == EXPECTED_BYTES