Skip to content

Commit f14ecde

Browse files
committed
fix(config): default profiles is empty array, not nil
config.Default() set Media.Profiles to nil, which encoding/json emits as "profiles": null. ONVIF clients and downstream JSON consumers expect that field to always be an array — null vs [] is a needless schema gotcha. Initialize with an empty slice so the on-disk shape is "profiles": []. Add TestDefaultProfilesIsEmptyArrayNotNull to lock both the in- memory non-nil-ness and the marshaled JSON form. Replace the hardcoded Version: 1 fixture literal with config.CurrentVersion in cmd/cli/control_test.go, internal/simulator/{simulator,rtsp}_test.go, and internal/tui/{adapter,mock}_test.go so a future schema bump fails the tests at compile time rather than silently passing with a stale literal.
1 parent e8260d1 commit f14ecde

7 files changed

Lines changed: 33 additions & 6 deletions

File tree

cmd/cli/control_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ func writeTempConfig(t *testing.T) (cfgPath string, cleanup func()) {
2424
t.Helper()
2525
dir := t.TempDir()
2626
cfg := config.Config{
27-
Version: 1,
27+
Version: config.CurrentVersion,
2828
Device: config.DeviceConfig{
2929
UUID: "urn:uuid:00000000-0000-4000-8000-000000000001",
3030
Manufacturer: "Test", Model: "SimCam", Serial: "SN-1",

internal/config/config.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -923,7 +923,10 @@ func Default() Config {
923923
},
924924
},
925925
Network: NetworkConfig{HTTPPort: 8080, RTSPPort: DefaultRTSPPort},
926-
Media: MediaConfig{Profiles: nil},
926+
// Use an empty slice (not nil) so json.Marshal emits
927+
// "profiles": [] rather than "profiles": null. ONVIF clients
928+
// and JSON consumers expect the field to always be an array.
929+
Media: MediaConfig{Profiles: []ProfileConfig{}},
927930
Events: EventsConfig{
928931
MaxPullPoints: defaultMaxPullPoints,
929932
SubscriptionTimeout: "1h",

internal/config/path_test.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
package config_test
22

33
import (
4+
"encoding/json"
45
"errors"
56
"os"
67
"path/filepath"
78
"runtime"
9+
"strings"
810
"sync"
911
"testing"
1012

@@ -147,6 +149,28 @@ func TestDefaultPassesValidate(t *testing.T) {
147149
}
148150
}
149151

152+
// TestDefaultProfilesIsEmptyArrayNotNull pins the JSON shape of
153+
// Default(): media.profiles must marshal to "[]" rather than "null"
154+
// so ONVIF clients (and json-schema-style consumers) always see an
155+
// array. A nil slice would emit "null" and break that contract.
156+
func TestDefaultProfilesIsEmptyArrayNotNull(t *testing.T) {
157+
t.Parallel()
158+
cfg := config.Default()
159+
if cfg.Media.Profiles == nil {
160+
t.Fatal("Default().Media.Profiles is nil; expected an empty slice")
161+
}
162+
if len(cfg.Media.Profiles) != 0 {
163+
t.Fatalf("Default().Media.Profiles is not empty: %+v", cfg.Media.Profiles)
164+
}
165+
data, err := json.Marshal(cfg.Media)
166+
if err != nil {
167+
t.Fatalf("marshal: %v", err)
168+
}
169+
if !strings.Contains(string(data), `"profiles":[]`) {
170+
t.Errorf("expected profiles to marshal as [], got: %s", string(data))
171+
}
172+
}
173+
150174
// TestDefaultUUIDIsUnique guards against the original hardcoded
151175
// urn:uuid:00000000-0000-4000-8000-000000000001 sneaking back in. Two
152176
// successive Default() calls must not collide; ONVIF clients (and

internal/simulator/rtsp_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ func newSimulatorWithMediaFile(t *testing.T, mediaPath string) (sim *Simulator,
3939
cfgPath := filepath.Join(dir, config.FileName)
4040

4141
cfg := config.Config{
42-
Version: 1,
42+
Version: config.CurrentVersion,
4343
Device: config.DeviceConfig{
4444
UUID: "urn:uuid:00000000-0000-4000-8000-000000000001",
4545
Manufacturer: "Test",

internal/simulator/simulator_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ func newTestSimulator(t *testing.T) (sim *Simulator, cleanup func()) {
4444
cfgPath := filepath.Join(dir, config.FileName)
4545

4646
cfg := config.Config{
47-
Version: 1,
47+
Version: config.CurrentVersion,
4848
Device: config.DeviceConfig{
4949
UUID: "urn:uuid:00000000-0000-4000-8000-000000000001",
5050
Manufacturer: "Test",

internal/tui/adapter_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ func newTestAdapter(t *testing.T) (sa *simulatorAdapter, cleanup func()) {
3131
}
3232

3333
cfg := config.Config{
34-
Version: 1,
34+
Version: config.CurrentVersion,
3535
Device: config.DeviceConfig{
3636
UUID: "urn:uuid:00000000-0000-4000-8000-aaaaaaaaaaaa",
3737
Manufacturer: "Test",

internal/tui/mock_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ type mockSim struct {
2323
func newMockSim() *mockSim {
2424
return &mockSim{
2525
snapshot: config.Config{
26-
Version: 1,
26+
Version: config.CurrentVersion,
2727
Device: config.DeviceConfig{
2828
UUID: "urn:uuid:11111111-1111-1111-1111-111111111111",
2929
Manufacturer: "Acme",

0 commit comments

Comments
 (0)