fix(server): failed transcoded files should not be cached (#4124)

* Close stream on caching errors

* fix(test): replace errPartialReader with errFakeReader to fix lint error

Signed-off-by: Deluan <deluan@navidrome.org>

* fix(test): update error assertion to check for substring in closed file error

Signed-off-by: Deluan <deluan@navidrome.org>

---------

Signed-off-by: Deluan <deluan@navidrome.org>
This commit is contained in:
Deluan Quintão 2025-05-26 20:30:26 -04:00 committed by GitHub
parent 030710afa9
commit 9dd5a8c334
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 18 additions and 8 deletions

View File

@ -174,6 +174,7 @@ func (fc *fileCache) Get(ctx context.Context, arg Item) (*CachedStream, error) {
go func() {
if err := copyAndClose(w, reader); err != nil {
log.Debug(ctx, "Error storing file in cache", "cache", fc.name, "key", key, err)
_ = r.Close()
_ = fc.invalidate(ctx, key)
} else {
log.Trace(ctx, "File successfully stored in cache", "cache", fc.name, "key", key)

View File

@ -116,18 +116,16 @@ var _ = Describe("File Caches", func() {
})
})
When("reader returns error", func() {
It("does not cache", func() {
It("does not cache and closes the stream", func() {
fc := callNewFileCache("test", "1KB", "test", 0, func(ctx context.Context, arg Item) (io.Reader, error) {
return errFakeReader{errors.New("read failure")}, nil
return &errFakeReader{data: []byte("data"), err: errors.New("read failure")}, nil
})
s, err := fc.Get(context.Background(), &testArg{"test"})
Expect(err).ToNot(HaveOccurred())
_, _ = io.Copy(io.Discard, s)
// TODO How to make the fscache reader return the underlying reader error?
//Expect(err).To(MatchError("read failure"))
_, err = io.ReadAll(s)
Expect(err.Error()).To(ContainSubstring("file already closed"))
// Data should not be cached (or eventually be removed from cache)
Eventually(func() bool {
s, _ = fc.Get(context.Background(), &testArg{"test"})
if s != nil {
@ -145,6 +143,17 @@ type testArg struct{ s string }
func (t *testArg) Key() string { return t.s }
type errFakeReader struct{ err error }
type errFakeReader struct {
data []byte
err error
off int
}
func (e errFakeReader) Read([]byte) (int, error) { return 0, e.err }
func (e *errFakeReader) Read(b []byte) (int, error) {
if e.off < len(e.data) {
n := copy(b, e.data[e.off:])
e.off += n
return n, nil
}
return 0, e.err
}