Files
soldosluka857 b2ccd04844 fix(dlna): always return non-nil device slice so API serializes [] not null
The DLNA device list endpoint could return {"devices":null} in two cases:
the SSDP-failure path returned a nil slice, and the cached path copied an
empty cache via append([]DLNADevice(nil), cache...) which also yields nil.
The web UI reads res.devices.length, so a null devices field crashed the
DLNA page to a white screen. Return non-nil slices in both paths and guard
the frontend with a null coalesce. Adds a regression test.

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-05-30 13:02:16 +08:00

38 lines
1.1 KiB
Go

package service
import (
"context"
"encoding/json"
"testing"
"time"
"go.uber.org/zap"
)
// TestDLNADiscoverCachedEmptyReturnsNonNil guards against the bug where an
// empty device cache was copied via append([]DLNADevice(nil), cache...),
// which yields a nil slice and serializes to JSON null. The web UI reads
// res.devices.length, so a null devices field crashed the DLNA page.
func TestDLNADiscoverCachedEmptyReturnsNonNil(t *testing.T) {
d := NewDLNAService(zap.NewNop())
// Prime the cache with an empty (but non-nil) result, fresh enough to be served.
d.cache = []DLNADevice{}
d.cachedAt = time.Now()
out, err := d.Discover(context.Background(), false)
if err != nil {
t.Fatalf("Discover returned error: %v", err)
}
if out == nil {
t.Fatal("Discover returned nil slice for empty cache; want non-nil so JSON is [] not null")
}
b, err := json.Marshal(map[string]any{"devices": out})
if err != nil {
t.Fatalf("marshal: %v", err)
}
if got := string(b); got != `{"devices":[]}` {
t.Fatalf("devices serialized as %s; want {\"devices\":[]}", got)
}
}