fix: a track shorter than the fingerprint span keeps its print (#6178)
release / govulncheck (push) Successful in 16s
release / web (push) Successful in 1m26s
release / go (push) Successful in 1m43s
release / integration (push) Successful in 5m14s
release / android (push) Successful in 5m15s
release / Build signed APK (releases and dev) (push) Successful in 5m20s
release / Attach APK to the Release (tag releases only) (push) Skipped
release / Build + push container image (push) Successful in 1m18s
release / Verify release artifacts (tag releases only) (push) Skipped
release / govulncheck (push) Successful in 16s
release / web (push) Successful in 1m26s
release / go (push) Successful in 1m43s
release / integration (push) Successful in 5m14s
release / android (push) Successful in 5m15s
release / Build signed APK (releases and dev) (push) Successful in 5m20s
release / Attach APK to the Release (tag releases only) (push) Skipped
release / Build + push container image (push) Successful in 1m18s
release / Verify release artifacts (tag releases only) (push) Skipped
The image's fpcalc 1.5.1 exits 3 with "Error decoding audio frame (End of file)" whenever it reaches the end of a file before -length, at any length, so every track under two minutes failed both the AcoustID lookup print and the duplicate-detection print: 471 lookups and all 1,979 present short tracks' chromaprints. - runFingerprintTool returns the tool's stdout beside a toolExitError. - fpcalcReadToEnd keeps a partial exit whose stderr is the end of file and whose declared DURATION is within the span asked for. A damaged file that stops early declares more than it read, and still fails. - Migration 0097 clears the stored failures so the lookup worker and the fingerprint backfill take those tracks again. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -253,3 +253,45 @@ func TestFingerprintResult_InconclusiveIfEitherHalfIs(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// fpcalc 1.5.1 exits 3 with "(End of file)" on every file shorter than the
|
||||
// span asked for (#6178). That print covers the whole file and is kept; a file
|
||||
// whose declared length runs past the span stopped early, and is not.
|
||||
func TestFpcalcReadToEnd(t *testing.T) {
|
||||
eof := []byte("ERROR: Error decoding audio frame (End of file)")
|
||||
out := func(sec int) []byte { return []byte(fmt.Sprintf("DURATION=%d\nFINGERPRINT=AQAB\n", sec)) }
|
||||
for name, tc := range map[string]struct {
|
||||
err error
|
||||
out []byte
|
||||
want bool
|
||||
}{
|
||||
"short file read to its end": {&toolExitError{name: "fpcalc", code: 3, stderr: eof}, out(37), true},
|
||||
"exactly the span": {&toolExitError{name: "fpcalc", code: 3, stderr: eof}, out(120), true},
|
||||
"declared longer than read": {&toolExitError{name: "fpcalc", code: 3, stderr: eof}, out(150), false},
|
||||
"partial for another reason": {&toolExitError{name: "fpcalc", code: 3, stderr: []byte("ERROR: invalid data")}, out(37), false},
|
||||
"a different exit": {&toolExitError{name: "fpcalc", code: 2, stderr: eof}, out(37), false},
|
||||
"no duration printed": {&toolExitError{name: "fpcalc", code: 3, stderr: eof}, []byte("FINGERPRINT=AQAB\n"), false},
|
||||
"not a tool exit (a stall)": {fmt.Errorf("fpcalc: %w", errFingerprintTimeout), out(37), false},
|
||||
"wrapped exit is still judged": {fmt.Errorf("lookup: %w", &toolExitError{name: "fpcalc", code: 3, stderr: eof}), out(37), true},
|
||||
} {
|
||||
if got := fpcalcReadToEnd(tc.err, tc.out, 120); got != tc.want {
|
||||
t.Errorf("%s: fpcalcReadToEnd = %v, want %v", name, got, tc.want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// The output of a tool that exited non-zero reaches the caller, or
|
||||
// fpcalcReadToEnd has nothing to read; the message is unchanged.
|
||||
func TestRunFingerprintTool_KeepsOutputOnExit(t *testing.T) {
|
||||
out, err := runFingerprintTool(context.Background(), "sh",
|
||||
[]string{"-c", "echo DURATION=37; echo 'ERROR: Error decoding audio frame (End of file)' >&2; exit 3"})
|
||||
if err == nil {
|
||||
t.Fatal("exit 3 returned no error")
|
||||
}
|
||||
if want := "sh exited 3: ERROR: Error decoding audio frame (End of file)"; err.Error() != want {
|
||||
t.Errorf("err = %q, want %q", err, want)
|
||||
}
|
||||
if d, ok := fpcalcDuration(out); !ok || d != 37 {
|
||||
t.Errorf("output = %q, want the DURATION line kept", out)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user