Files
espresso_frame/server/tests/test_frame_preview.py
T
tfaour 9c8a87e90d
Build and push server image / test (push) Successful in 22s
Build and push server image / build-and-push (push) Successful in 1m59s
Build and push server image / deploy (push) Successful in 48s
Add a live preview thumbnail next to the frame name
Small header thumbnail showing exactly what the frame is currently
displaying -- same widget compositor /frame/image uses, handed back as
a plain PNG (image_pipeline.render_panel/render_placeholder gain an
as_png option) instead of packed native-panel bytes. New session-authed
GET /api/frames/{id}/preview exposes it; click-to-refresh plus a slow
60s poll on the frame header so it doesn't hammer Immich/calendar
sources just for a header thumbnail.
2026-07-24 15:55:59 -04:00

72 lines
2.4 KiB
Python

"""GET /api/frames/{id}/preview -- the dashboard header's live "how it's
displaying" thumbnail (see routers/device.py's render_frame_preview_png).
Same compositor as /frame/image, just PNG instead of packed bytes, and
gated by require_frame_view instead of device auth -- so the interesting
things to check are that it's a real PNG of the right logical size and
that view-only auth (not device auth) actually applies."""
from __future__ import annotations
import io
from PIL import Image
from app.image_pipeline import logical_render_size
from app.models import Frame
from .conftest import link_user, login, make_user
def test_preview_returns_a_png_at_logical_size(client, db_session):
client.post("/setup", data={"username": "alice", "password": "hunter22"})
frame = db_session.get(Frame, 1)
resp = client.get("/api/frames/1/preview")
assert resp.status_code == 200
assert resp.headers["content-type"] == "image/png"
img = Image.open(io.BytesIO(resp.content))
assert img.size == logical_render_size(frame.orientation)
def test_preview_reflects_orientation(client, db_session):
client.post("/setup", data={"username": "alice", "password": "hunter22"})
frame = db_session.get(Frame, 1)
frame.orientation = "portrait"
db_session.commit()
resp = client.get("/api/frames/1/preview")
assert resp.status_code == 200
img = Image.open(io.BytesIO(resp.content))
assert img.size == logical_render_size("portrait")
assert img.width < img.height
def test_preview_visible_to_linked_user(client, db_session):
client.post("/setup", data={"username": "alice", "password": "hunter22"})
bob = make_user(db_session, "bob")
frame = db_session.get(Frame, 1)
link_user(db_session, bob, frame)
client.cookies.clear()
login(client, "bob")
resp = client.get("/api/frames/1/preview")
assert resp.status_code == 200
def test_preview_hidden_from_unrelated_user(client, db_session):
client.post("/setup", data={"username": "alice", "password": "hunter22"})
make_user(db_session, "mallory")
client.cookies.clear()
login(client, "mallory")
resp = client.get("/api/frames/1/preview")
assert resp.status_code == 404
def test_preview_requires_login(client, db_session):
client.post("/setup", data={"username": "alice", "password": "hunter22"})
client.cookies.clear()
resp = client.get("/api/frames/1/preview")
assert resp.status_code in (401, 403)