e2e: drive the real binary against synthesized media - #26
Merged
Conversation
The 0x30 clobber fix could not be verified live: the idle DJM-A9 never emits 0x30 status packets, so the flip only reproduces with the full rig. Cover it deterministically instead - the two mixer-status write paths move out of their socket loops into recordMixerChannels / recordMixerStatus (no behaviour change; recordMixerStatus returns the first-packet flag the listener logs on), and the test replays the newer-DJM interleaving with synthesized wire packets fed through the real parser: 0x03 channel state, then twenty interleaved stripped 0x30s that previously wiped ChannelStateKnown each time, plus a channel change mid-stream. Reverting the merge makes the test fail on the first 0x30, so it pins the actual bug. Also covered: a rich legacy 0x29 replaces the entry wholesale, a lone 0x30 before any 0x03 leaves channel state honestly unknown, and the first-packet log flag fires exactly once.
An end-to-end suite for the flows that until now could only be verified by hand before a release. Run with make e2e (gated on VYNULL_E2E=1 so go test ./... stays fast); the suite skips itself when the DJ-Link UDP ports are held by a running instance. The harness builds the binary once, launches one server per test on a free port with an isolated temp data-dir, and synthesizes all of its own media: deterministic kick-train WAVs whose ground-truth BPM makes the integer-snap assertion exact, an ffmpeg-produced FLAC for the lossless path, and an MP3 with an embedded JPEG cover for the artwork path. No fixtures, no dependence on a local music library. Five scenarios covering the main user-facing flows: the analysis pipeline (rows fill, detected BPM lands exactly on the known integers including FLAC, waveform PNGs serve), lazy artwork (embedded art on first request, artless tracks 404 once and stay probed, directory cover.jpg fallback), playlist membership (wholesale set-tracks removal leaves library rows intact, smart rules resolve, delete leaves the library alone), the analysis-cache upgrade path (a manufactured stale-cacheVersion cache entry with a stale fractional row BPM re-analyzes on first touch and the row follows, while a manual BPM override survives), and a bulk-add pass whose polling loop is itself the responsiveness assertion. Writing the artwork scenario surfaced that ExtractArtwork's directory fallback applies to any artless file beside a cover image - now an explicit assertion rather than an accident. Full suite runs in ~15s.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What & why
Two commits adding automated end-to-end coverage for flows that until now could only be verified by hand before a release.
The first covers the one recent fix that could not be verified live: the 0x30 mixer-status merge. An idle DJM never emits 0x30 packets, so the state-clobbering flip only reproduces with a full rig. The two mixer-status write paths move out of their socket loops into recordMixerChannels / recordMixerStatus (no behaviour change), and a test replays the newer-DJM interleaving with synthesized wire packets fed through the real parser: 0x03 channel state, then twenty interleaved stripped 0x30s that previously wiped ChannelStateKnown each time, plus a channel change mid-stream. Reverting the merge makes the test fail on the first 0x30, so it pins the actual bug, not the implementation. Also covered: a rich legacy 0x29 replaces the entry wholesale, a lone 0x30 before any 0x03 leaves channel state honestly unknown, and the first-packet log flag fires exactly once.
The second is the e2e package, run with make e2e (gated on VYNULL_E2E=1 so go test ./... stays fast). The harness builds the real binary once, launches one server per test on a free port with an isolated temp data-dir, skips itself when the DJ-Link UDP ports are held by a running instance, and synthesizes all of its own media: deterministic kick-train WAVs whose ground-truth BPM makes the integer-snap assertion exact, plus ffmpeg-produced FLAC (the lossless path) and an MP3 with an embedded JPEG cover. No fixtures, no dependence on a local music library.
Five scenarios covering the main user-facing flows: the analysis pipeline (rows fill, BPM lands exactly on the known integers including FLAC, waveform PNGs serve); lazy artwork (embedded art on first request, artless tracks 404 once and stay probed, directory cover.jpg fallback); playlist membership (wholesale set-tracks removal leaves library rows intact, smart rules resolve, delete leaves the library alone); the analysis-cache upgrade path (a manufactured stale-cacheVersion cache entry with a stale fractional row BPM re-analyzes on first touch and the row follows, while a manual BPM override survives — reproducing what a cacheVersion bump looks like on disk without binary fixtures that rot); and a bulk-add pass whose polling loop is itself the responsiveness assertion. Full suite runs in about 15 seconds.
Writing the artwork scenario surfaced that ExtractArtwork's directory fallback applies to any artless file beside a cover image; that is now an explicit assertion rather than an accident.
What deliberately stays out of scope: web UI wiring (no browser toolchain committed), real-music breadth (a genuinely fractional track keeping its fraction is the one thing synthetic media cannot cover), large-library upgrade runs, and everything deck-facing — hardware behaviour still needs hardware.
Hardware testing
Checklist
go build ./...,go vet ./..., andgo test ./...passgofmt -l .is cleanGPL-3.0-or-later)