Documentation
¶
Overview ¶
Package fixtures synthesizes the tiny audio files WaxDeck's tests run against. The repository policy is "no binary media in git": every test asset is generated at test-setup from a Spec: a deterministic sine tone encoded through WaxFlow's own encoders and muxers. No external tools are involved. Output is byte-deterministic: the same Spec always yields the same file.
Library use:
paths, err := fixtures.Generate(dir, fixtures.DefaultLibrary()...)
CLI use:
go run ./cmd/fixturegen -out testdata/media
Index ¶
- Constants
- func Generate(dir string, specs ...Spec) ([]string, error)
- func GenerateBook(dir string) (string, error)
- func GenerateChapteredBook(dir string) (string, error)
- func GenerateExoticCover(dir string) (string, error)
- func GeneratePodcastFeed(dir string, feed FeedSpec, baseURL string) (string, error)
- type Chapter
- type Codec
- type Container
- type Corruption
- type EpisodeSpec
- type FeedSpec
- type Spec
Constants ¶
const ( ExoticCoverWidth = 240 ExoticCoverHeight = 180 )
ExoticCoverWidth and ExoticCoverHeight are what a test asserts the catalog measured. Not square, so a cover reported as 240 x 180 proves the dimensions were read rather than guessed from one number.
const ExoticCoverName = "sleeve.tiff"
ExoticCoverName is the file GenerateExoticCover writes. The extension is what a picker filters on, so it has to be one the app offers.
const MaxDuration = 10 * time.Second
MaxDuration bounds a Spec's synthesized audio, silence included. Fixtures exist to be tiny; anything longer is a misuse this package refuses.
Variables ¶
This section is empty.
Functions ¶
func Generate ¶
Generate synthesizes each spec into dir (created if absent) and returns the written paths, in spec order. It stops at the first failure, returning the paths written so far alongside the error.
func GenerateBook ¶
GenerateBook writes a three-part audiobook under dir using the conventional Author/Title layout: "Ada Author/The Fixture Book" holding parts "01 - Part One.m4b" through "03 - Part Three.m4b". The parts share ALBUM and ALBUMARTIST and carry track numbers, so a WaxBin scan groups them into one book item with three files in reading order. Tone durations are distinct per part so fingerprint dedup cannot merge them. It returns the book's directory.
func GenerateChapteredBook ¶
GenerateChapteredBook writes a single-file audiobook into dir: one .m4b whose MP4 container embeds three chapter markers, with book tags (album is the book title, album-artist the author). The tone duration differs from every GenerateBook part so the two books never share an essence. It returns the file's path.
func GenerateExoticCover ¶
GenerateExoticCover writes a TIFF cover into dir and returns its path.
TIFF is the useful format to test with: it is the one the catalog decodes and the Go standard library does not, so a cover that reaches the slot measured proves the artwork guard asked the catalog's own recognizer rather than http.DetectContentType.
func GeneratePodcastFeed ¶
GeneratePodcastFeed writes the feed's episode audio (through the same Generate machinery every fixture uses), any transcript (<guid>.vtt) and chapter (<guid>.chapters.json) sidecar documents, and a feed.xml tying them together: RSS 2.0 with the itunes and podcast namespaces, enclosure URLs rooted at baseURL. It returns the path of feed.xml.
Types ¶
type Chapter ¶
Chapter is one chapter marker to embed where the container supports them (MP4 today).
type Container ¶
type Container string
Container names the file container a Spec's codec is muxed into.
const ( // ContainerDefault selects the codec's default container: WAV for // PCM, ADTS for AAC, MP4 for ALAC, Ogg for Opus and Vorbis, and // the codec's own stream form for FLAC and MP3. ContainerDefault Container = "" ContainerWAV Container = "wav" ContainerAIFF Container = "aiff" ContainerFLAC Container = "flac" ContainerMP3 Container = "mp3" ContainerMP4 Container = "mp4" ContainerADTS Container = "adts" ContainerOgg Container = "ogg" ContainerMatroska Container = "mka" )
type Corruption ¶
type Corruption string
Corruption selects a deliberately malformed flavor of a Spec, for robustness tests. Corrupt fixtures are synthesized like everything else; no binary media is vendored.
const ( // CorruptNone produces a valid file. CorruptNone Corruption = "" // CorruptTruncated produces the valid encode cut off at half its // length: headers survive, the stream ends mid-file. CorruptTruncated Corruption = "truncated" // CorruptGarbage produces deterministic junk bytes under the spec's // file extension: no valid magic, no parsable structure. Garbage // needs no encoder, so it never requires ffmpeg. CorruptGarbage Corruption = "garbage" )
type EpisodeSpec ¶
type EpisodeSpec struct {
Title string
GUID string
Spec Spec
PubDate time.Time
Description string
TranscriptVTT string
ChaptersJSON string
}
EpisodeSpec describes one podcast episode: its synthesized audio plus the feed-level fields an aggregator reads. TranscriptVTT and ChaptersJSON are optional; when set, the sidecar documents are written next to the audio and the feed advertises them via the podcast namespace.
type FeedSpec ¶
type FeedSpec struct {
Title string
Author string
Description string
Link string
Episodes []EpisodeSpec
}
FeedSpec describes one podcast feed: channel fields plus its episodes. Link is the channel's home URL; empty falls back to the base URL the feed is generated against.
func DefaultPodcastFeed ¶
DefaultPodcastFeed is the preset feed the end-to-end harness serves: three MP3 episodes with silence-padded audio and distinct tone lengths (so essence dedup cannot merge them), descending publish dates from a fixed base so goldens stay stable, and a transcript plus chapters document on the first episode. baseURL becomes the channel link; the enclosure URLs come from the baseURL passed to GeneratePodcastFeed.
type Spec ¶
type Spec struct {
// Name overrides the generated file's base name (without the
// extension). Empty derives a deterministic name from the fields.
Name string
// Codec selects the audio codec. Required.
Codec Codec
// Container selects the file container; ContainerDefault picks the
// codec's native one.
Container Container
// Duration is the length of the synthesized tone, capped at
// MaxDuration to keep fixtures tiny; 0 means 1 second.
Duration time.Duration
// LeadSilence prepends literal zero samples before the tone. Zero
// means none; the output is then byte-identical to a spec without
// the field. LeadSilence + Duration + TrailSilence must stay within
// MaxDuration.
LeadSilence time.Duration
// TrailSilence appends literal zero samples after the tone. Zero
// means none.
TrailSilence time.Duration
// SampleRate is in Hz; 0 means 44100 (48000 for Opus, which always
// runs at 48 kHz anyway).
SampleRate int
// Channels is the channel count; 0 means 2 (stereo).
Channels int
// Corrupt selects a malformed flavor; the zero value is a valid file.
Corrupt Corruption
// Tags are metadata fields (TITLE, ARTIST, ...) embedded where the
// container has a stream form for them. Keys are written in sorted
// order so tagged output stays deterministic.
Tags map[string]string
// Chapters are chapter markers, embedded where the container
// supports them.
Chapters []Chapter
}
Spec describes one fixture file to synthesize.
func ConformanceMedia ¶
func ConformanceMedia() []Spec
ConformanceMedia returns the single tone the audio-engine conformance suite plays against real engines: long enough that mid-file seek targets are meaningfully far apart, still under the duration cap.
func DefaultLibrary ¶
func DefaultLibrary() []Spec
DefaultLibrary is the preset covering the full supported codec/container matrix (PCM in WAV and AIFF, FLAC in its stream form and in Matroska, MP3, AAC in ADTS and MP4, ALAC in MP4, Opus in Ogg, and Vorbis in Ogg), plus one truncated and one garbage flavor. Specs are fully spelled out (no zero-value defaults) so callers can read expected properties off them.
func DemoLibrary ¶
func DemoLibrary() []Spec
DemoLibrary is a small tagged album: one track per commonly streamed codec, titled so tests and humans can find them by name. End-to-end harnesses scan it alongside DefaultLibrary. Durations are distinct on purpose: a catalog's fingerprint dedup would otherwise merge these with the matrix files, which synthesize the same tone at the same length.
func UploadFolderSources ¶
func UploadFolderSources() []Spec
UploadFolderSources is the folder-pick journey's source material, which has to be its own album: the folder test and the file test run against one server, and reusing UploadSources would have each one importing the other's release and racing it for the destination. Distinct durations again, for the fingerprint-dedup reason.
Written under a disc subdirectory by the e2e stack, so what the pick walks is a tree rather than a flat folder - which is the half of a folder upload a flat one would never prove.
func UploadSources ¶
func UploadSources() []Spec
UploadSources is the manual-upload journey's source material: a two-track album plus a standalone single, whose artists, albums, and titles appear in no other preset, so an end-to-end import can assert them uniquely against the scanned library. The single is the declined-identify journey's own file - declining imports on arrival, so a file another upload test imports would race it for the destination and flag it as a duplicate. Durations are distinct from every other preset for the same fingerprint-dedup reason as DemoLibrary.
func UploadWorkbenchSources ¶
func UploadWorkbenchSources() []Spec
UploadWorkbenchSources is the release-workbench journey's own album, its own for the UploadFolderSources reason: that journey imports and then renames a release, and had it reused the lantern album its import would hold the destination the manual-upload journey's own import needs (the rename regroups the catalog but moves no files). Distinct durations, same fingerprint-dedup reason as everywhere.
Directories
¶
| Path | Synopsis |
|---|---|
|
cmd
|
|
|
corpusgen
command
Command corpusgen synthesizes a large catalog corpus for performance gates: real audio files, each carrying a cue sheet that carves it into first-class virtual tracks at scan.
|
Command corpusgen synthesizes a large catalog corpus for performance gates: real audio files, each carrying a cue sheet that carves it into first-class virtual tracks at scan. |
|
feedserv
command
Command feedserv serves a directory of podcast-feed fixtures over HTTP for the end-to-end harness: feed.xml, episode audio, transcript and chapter documents, with correct content types, Range support, and ETag/Last-Modified conditional GETs so feed polling behaves like it does against a real host.
|
Command feedserv serves a directory of podcast-feed fixtures over HTTP for the end-to-end harness: feed.xml, episode audio, transcript and chapter documents, with correct content types, Range support, and ETag/Last-Modified conditional GETs so feed polling behaves like it does against a real host. |
|
fixturegen
command
Command fixturegen writes a synthesized fixture library to a directory and prints the file list, one path per line.
|
Command fixturegen writes a synthesized fixture library to a directory and prints the file list, one path per line. |
|
sourceserv
command
Command sourceserv serves a canned acquisition source for the end-to-end harness: a playlist manifest at /playlist and the entry audio at /audio/<id>, synthesized at startup with -generate.
|
Command sourceserv serves a canned acquisition source for the end-to-end harness: a playlist manifest at /playlist and the entry audio at /audio/<id>, synthesized at startup with -generate. |
|
testidp
command
Command testidp is a minimal OIDC identity provider for the end-to-end harness: discovery, JWKS, an interactive login form on the authorization endpoint, and a token endpoint that enforces PKCE (S256) and single-use codes.
|
Command testidp is a minimal OIDC identity provider for the end-to-end harness: discovery, JWKS, an interactive login form on the authorization endpoint, and a token endpoint that enforces PKCE (S256) and single-use codes. |