Vellum/internal/jellyfin
mithral 608ac5c6d6 Close the Jellyfin test gap
internal/jellyfin is the most client-visible surface in the tree — real Jellyfin
apps parse its JSON — and it had zero test files. Phase 2 had just moved its
DTOs, so this closes the gap before the next refactor.

Coverage: internal/jellyfin 0.0% -> 35.7%, internal/jellyfin/dto -> 68.9%.

The tests, and why each exists:

- Credential forms. X-Emby-Token, X-MediaBrowser-Token, ?api_key= and
  Authorization: MediaBrowser Token="...". The query form matters most: <video>
  and <audio> elements cannot set headers, so a client that can only use
  ?api_key= must still authenticate.
- Grant scoping. A user with no grants sees zero items, and an item they cannot
  read returns a response BYTE-IDENTICAL to one that does not exist. A 403 would
  confirm the library is there and leak its existence. The test asserts the two
  responses are indistinguishable, not merely both non-200.
- The transcode refusal. A client that disables both direct play and direct
  stream is demanding a transcode, and gets ErrorCode NoCompatibleStream rather
  than a TranscodingUrl that would never resolve. The normal path is asserted to
  advertise SupportsTranscoding FALSE, because a client told otherwise waits
  forever for a stream that never starts.
- Streaming with ONLY ?api_key= plus a Range header returns 206 with a correct
  Content-Range and the right bytes, and a token cannot stream a file it cannot
  read.
- AuthenticateByName mints a token that then authenticates, and returns no token
  for bad credentials.
- DTO mapping: exact JSON key set, RunTimeTicks as ms x 10000, id round-trip,
  ImageTags only with a cover, and golden JSON for both the item and the media
  source.

Both halves are proven able to FAIL, because a test that cannot fail is
decoration:
  - flipping SupportsTranscoding to true fails TestMediaSourceNeverTranscodes
  - disabling the grant check in catalog.LoadFor fails
    TestGrantScopingIsIndistinguishableFromAbsent AND TestStreamRefusesUnreadableItem
Both were restored afterwards and the non-test files verified byte-unchanged.

Process note: the agent for this task failed twice (HTTP 400) and left a test
file that did not compile — a bad slices.Delete call and a helper it never
wrote. I fixed those, corrected one wrong expectation (a video item legitimately
carries MediaType; the test's want-list omitted it), and wrote the handler tests
myself since that was the half that never got reached.

gofmt clean, build exit 0, vet exit 0, 25 packages pass, svelte-check 0/0.
2026-10-11 16:10:58 -04:00
..
dto Close the Jellyfin test gap 2026-10-11 16:10:58 -04:00
auth.go Waves 9-10: Jellyfin and Subsonic clients can browse and play 2026-10-11 15:05:43 -04:00
items.go Phase 2: split the fat packages along real boundaries 2026-10-11 16:03:10 -04:00
jellyfin.go Waves 9-10: Jellyfin and Subsonic clients can browse and play 2026-10-11 15:05:43 -04:00
jellyfin_test.go Close the Jellyfin test gap 2026-10-11 16:10:58 -04:00
playback.go Phase 2: split the fat packages along real boundaries 2026-10-11 16:03:10 -04:00
query.go Phase 2: split the fat packages along real boundaries 2026-10-11 16:03:10 -04:00
sessions.go Phase 2: split the fat packages along real boundaries 2026-10-11 16:03:10 -04:00
system.go Phase 2: split the fat packages along real boundaries 2026-10-11 16:03:10 -04:00