4 Commits

Author SHA1 Message Date
football2801 2a8bf3895f chore(dev): DDEV setup so the test suite actually runs
CI / test (push) Has been cancelled
Mirrors aqua-iq's pattern but adapted for pictureFrame's stack:
postgres 16, php 8.4, node 22, imagick + pcov via apt extras,
Mercure hub at https://pictureframe.ddev.site/.well-known/mercure,
and four custom commands — `ddev tests`, `ddev coverage`,
`ddev frontend` (vite HMR), `ddev worker`.

Also restores dev deps (DAMA, Doctrine fixtures, symfony/uid) that
got dropped during earlier composer reshuffles, and adds a separate
`db_test` connection in .env.test so DAMA's transactional isolation
doesn't share state with whatever dev is mid-experiment with.

Two test fixes the new env exposed:
  - RotationServiceTest::test_prioritize_never_shown_falls_through_when_all_shown
    needed uniquenessWindow=2 so the recent-window filter wipes the
    set and the fallback restores the full pool — otherwise window=1
    excluded the most-recently-served image and the assertion drifted.
  - DeviceImageControllerTest::test_locked_image_served_without_rotation_advance
    was asserting currentImage stays null on a lock poll, but the
    controller intentionally sets currentImage on the lock path so
    Home reflects the live frame state. Now asserts both the
    currentImage update AND that no DeviceImageHistory row was
    written (the actual rotation-bypass guarantee).

Backend coverage (full suite via `ddev coverage`): 89.08% lines /
92.24% methods / 74.36% classes — the first real number we've had.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-08 13:56:36 -04:00
football2801 b48ed73b4e fix(rotation): isDue() compares wakeTime boundary in UTC, not device-local tz
CI / test (push) Has been cancelled
Symptom: wakeTimes schedules silently never fire on non-UTC devices.
Reported live by Matt's EDT frame: wakeTimes=[12:30 PM NY] saved,
12:30 came and went, no rotation. Same bug pattern would fire
*every* poll on east-of-UTC tzs.

Root cause: device_image_history.served_at is `timestamp without time
zone`, written by `new DateTimeImmutable()` so it stores UTC
components ("2026-05-08 16:28:50"). The boundary in isDue() was
bound through Doctrine with the device's local tz still attached,
so Doctrine's format() emitted local-tz components ("12:30:00").
Postgres compared the strings literally — for west-of-UTC tzs the
UTC timestamp is numerically larger than the local-tz boundary, so
every same-day row falsely satisfied `servedAt >= :wakeTime` and
isDue returned false.

Fix: $boundary->setTimezone(UTC) before binding. Both sides now
format in UTC components, so Postgres's literal compare is correct.

Regression test ID-TZ-01: device in America/New_York, wakeTimes
[12:30 PM NY], history at 12:00 PM NY (= 16:00 UTC). With the fix
isDue returns true; without it the test falsely-matches and fails.
Skipped before 13:00 NY since the assertion needs the wake slot to
have already passed today.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-08 12:41:40 -04:00
football2801 bf9d4ebc58 test: close coverage gaps from the recent rotation + Mercure work
CI / test (push) Has been cancelled
Frontend (90.15→95.37 stmts / 91.83→97.01 lines):
  - useDeviceMercure: full composable test suite via a fake EventSource —
    open/merge/ignore-stale/parse-error/reconnect/dynamic-add/remove/
    no-op-when-unconfigured/cleanup-on-unmount.
  - HomeView: cover onTimePart's AM/PM and minute branches plus the
    nextPollExpectedAt-null fallback paths in the next-update preview.

Backend (no instrumentation before; pcov was already in the image,
just needed a <coverage> block in phpunit.dist.xml):
  - RotationService: one test per mode (NewestUpload, Random,
    LeastRecentlyShown), one for never-shown sorting first under LRS,
    and two for prioritizeNeverShown — narrows when never-shown exists,
    falls through to mode otherwise.
  - DeviceSerializer: contract test on the wire shape (REST + Mercure
    use the same serializer; silent rename here would break live updates
    instantly).
  - MercurePublisher: topic format + JSON encoding + the swallow-
    exceptions guarantee (a flaky hub must not break poll responses).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 17:25:25 -04:00
football2801 12245759ac chore: stage all in-progress work before repo split
CI / test (push) Has been cancelled
Web app: new entities (Image, RenderedAsset, SharedImage, Token,
DeviceImageHistory), enums, repositories, controllers, message handlers,
migrations, tests, frontend upload/library/sticker UI, Vue components.

Firmware: EPD background screen binaries + gen scripts, setup_bg header.

Infra: ddev config, test bundle, gitignore coverage dir.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-06 12:11:31 -04:00