Files
ImageApi/dev/e2e
Cameron CordesandClaude Opus 5.5 8fc512fef0 dev/e2e: wall_clock regression check + deterministic fixture dates
`e2e.sh check` compares every indexed fixture's manifest wall clock with
the `wall_clock` reported by /image/metadata, /memories and
/photos/gps-summary; any disagreement fails.

- Fixture videos are stamped like phone containers: the America/New_York
  wall as a UTC creation_time (the label previously showed the UTC time).
- mtimes are pinned in America/New_York instead of the host's zone.
- The e2e env sets TZ=America/New_York (the #120 preflight): the Windows
  exe has no /etc/timezone, so server_zone() was otherwise None.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 13:50:24 -04:00
..

e2e dev server

A disposable ImageApi instance with a known, synthetic media library, for end-to-end and agent-driven UI testing of the SynologyFileViewer app.

dev/e2e/e2e.sh up        # build + fixtures + reset + start; blocks until ingest is done
dev/e2e/e2e.sh reset     # back to the pristine baseline (after tests mutate things)
dev/e2e/e2e.sh stop
dev/e2e/e2e.sh check     # every fixture's displayed capture time (wall_clock) vs the manifest

Log in from the app with server http://10.0.2.2:8090 (Android emulator) or http://127.0.0.1:8090 (Expo web / adb reverse tcp:8090 tcp:8090), user e2e, password E2eTest#2026pass.

Isolation

It runs next to a real local server without touching it:

real server e2e server
exe target/debug/image-api.exe dev/e2e/.work/bin/image-api-e2e.exe (built in target/e2e)
port BIND_URL + localhost:8088 127.0.0.1:8090 only (LOCAL_BIND_URL= disables the 8088 bind)
data your .env dev/e2e/.work/state/ (db, thumbs, hls, gifs, previews, media)
AI configured off — Ollama points at a closed port

stop kills by image name image-api-e2e.exe, so it can't hit the real server. Everything under .work/ is gitignored and safe to delete.

Fixtures

gen_fixtures.py renders every image with its relative path, date and scenario burned into the pixels — a screenshot tells you exactly which fixture is on screen. .work/state/manifest.json lists every item with its expected date, GPS, camera, tags, duplicate relationship and expected wall_clock (the capture time the UI must show), plus expected counts; assert against it rather than hardcoding. Naive fixture times are walls in America/New_York (the e2e display and server zone); videos are stamped the way phones write containers (that wall, as a UTC creation_time).

Folder Covers
2019/2019-07-04 Beach Day, 2021/Paris Trip, 2022/Hiking EXIF dates, GPS (map), cameras, tags, mixed orientation
2022/Hiking/summit.mp4, Videos/ landscape + portrait video, HLS, container dates
2023/Birthday dated, no GPS
Grid Stress (60) scrolling / pagination
Screenshots date from filename only (filename source), PNG
Undated no date anywhere → pinned mtime (fs_time source)
On This Day memories: today's month/day in 2018/2020/2024
private EXCLUDED_DIRS — never indexed
Duplicates byte-identical copy of 2021/Paris Trip/IMG_1000.jpg
Empty Album folder with no media

"On This Day" is relative to the generation date — run e2e.sh fixtures --force && e2e.sh reset on a later day to keep memories populated. Tags from the manifest are seeded through the API on first start.

To test against real photos, e2e.sh fixtures --import /path/to/folder copies a folder into media/imported/ (the source is only read).

Extra configuration

Put server env overrides in dev/e2e/env.local (gitignored); it's appended to the generated .env on every reset. E.g. to exercise AI insights against the local llama-swap:

LLM_BACKEND=llamacpp
LLAMA_SWAP_URL=http://localhost:9292/v1

Env for the script itself: E2E_PORT, E2E_BIND (0.0.0.0 for a physical device on Wi-Fi), E2E_USER, E2E_PASS.

Notes for agents

  • WSL2 (NAT networking) can't reach Windows' 127.0.0.1; use curl.exe, or e2e.sh api GET 'photos?path=&recursive=true' / e2e.sh token.
  • Sort values are lowercase: sort=datetakendesc.
  • Rebuild after server changes with e2e.sh build (restarts if running).
  • Server log: .work/server.log.