diff --git a/src/go/plugin/go.d/modules/icecast/collect.go b/src/go/plugin/go.d/modules/icecast/collect.go index 833c2f872f..102ad31e52 100644 --- a/src/go/plugin/go.d/modules/icecast/collect.go +++ b/src/go/plugin/go.d/modules/icecast/collect.go @@ -11,19 +11,6 @@ import ( "github.com/netdata/netdata/go/plugins/plugin/go.d/pkg/web" ) -type ( - serverStats struct { - IceStats *struct { - Source []sourceStats `json:"source"` - } `json:"icestats"` - } - sourceStats struct { - ServerName string `json:"server_name"` - StreamStart string `json:"stream_start"` - Listeners int64 `json:"listeners"` - } -) - const ( urlPathServerStats = "/status-json.xsl" // https://icecast.org/docs/icecast-trunk/server_stats/ ) diff --git a/src/go/plugin/go.d/modules/icecast/icecast_test.go b/src/go/plugin/go.d/modules/icecast/icecast_test.go index 0542b6c0e1..40132986da 100644 --- a/src/go/plugin/go.d/modules/icecast/icecast_test.go +++ b/src/go/plugin/go.d/modules/icecast/icecast_test.go @@ -19,16 +19,18 @@ var ( dataConfigJSON, _ = os.ReadFile("testdata/config.json") dataConfigYAML, _ = os.ReadFile("testdata/config.yaml") - dataServerStats, _ = os.ReadFile("testdata/server_stats.json") - dataServerStatsNoSources, _ = os.ReadFile("testdata/server_stats_no_sources.json") + dataServerStatsMultiSource, _ = os.ReadFile("testdata/stats_multi_source.json") + dataServerStatsSingleSource, _ = os.ReadFile("testdata/stats_single_source.json") + dataServerStatsNoSources, _ = os.ReadFile("testdata/stats_no_sources.json") ) func Test_testDataIsValid(t *testing.T) { for name, data := range map[string][]byte{ - "dataConfigJSON": dataConfigJSON, - "dataConfigYAML": dataConfigYAML, - "dataServerStats": dataServerStats, - "dataServerStatsNoSources": dataServerStatsNoSources, + "dataConfigJSON": dataConfigJSON, + "dataConfigYAML": dataConfigYAML, + "dataServerStats": dataServerStatsMultiSource, + "dataServerStatsSingleSource": dataServerStatsSingleSource, + "dataServerStatsNoSources": dataServerStatsNoSources, } { require.NotNil(t, data, name) } @@ -80,9 +82,13 @@ func TestIcecast_Check(t *testing.T) { wantFail bool prepare func(t *testing.T) (*Icecast, func()) }{ - "success default config": { + "success multiple sources": { wantFail: false, - prepare: prepareCaseOk, + prepare: prepareCaseMultipleSources, + }, + "success single source": { + wantFail: false, + prepare: prepareCaseMultipleSources, }, "fails on no sources": { wantFail: true, @@ -122,14 +128,21 @@ func TestIcecast_Collect(t *testing.T) { wantMetrics map[string]int64 wantCharts int }{ - "success default config": { - prepare: prepareCaseOk, + "success multiple sources": { + prepare: prepareCaseMultipleSources, wantCharts: len(sourceChartsTmpl) * 2, wantMetrics: map[string]int64{ "source_abc_listeners": 1, "source_efg_listeners": 10, }, }, + "success single source": { + prepare: prepareCaseSingleSource, + wantCharts: len(sourceChartsTmpl) * 1, + wantMetrics: map[string]int64{ + "source_abc_listeners": 1, + }, + }, "fails on no sources": { prepare: prepareCaseNoSources, }, @@ -160,13 +173,32 @@ func TestIcecast_Collect(t *testing.T) { } } -func prepareCaseOk(t *testing.T) (*Icecast, func()) { +func prepareCaseMultipleSources(t *testing.T) (*Icecast, func()) { t.Helper() srv := httptest.NewServer(http.HandlerFunc( func(w http.ResponseWriter, r *http.Request) { switch r.URL.Path { case urlPathServerStats: - _, _ = w.Write(dataServerStats) + _, _ = w.Write(dataServerStatsMultiSource) + default: + w.WriteHeader(http.StatusNotFound) + } + })) + + icecast := New() + icecast.URL = srv.URL + require.NoError(t, icecast.Init()) + + return icecast, srv.Close +} + +func prepareCaseSingleSource(t *testing.T) (*Icecast, func()) { + t.Helper() + srv := httptest.NewServer(http.HandlerFunc( + func(w http.ResponseWriter, r *http.Request) { + switch r.URL.Path { + case urlPathServerStats: + _, _ = w.Write(dataServerStatsSingleSource) default: w.WriteHeader(http.StatusNotFound) } diff --git a/src/go/plugin/go.d/modules/icecast/server_stats.go b/src/go/plugin/go.d/modules/icecast/server_stats.go new file mode 100644 index 0000000000..404d125556 --- /dev/null +++ b/src/go/plugin/go.d/modules/icecast/server_stats.go @@ -0,0 +1,45 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +package icecast + +import ( + "encoding/json" + "fmt" +) + +type ( + serverStats struct { + IceStats *struct { + Source iceSource `json:"source"` + } `json:"icestats"` + } + iceSource []sourceStats + sourceStats struct { + ServerName string `json:"server_name"` + StreamStart string `json:"stream_start"` + Listeners int64 `json:"listeners"` + } +) + +func (i *iceSource) UnmarshalJSON(data []byte) error { + var v any + if err := json.Unmarshal(data, &v); err != nil { + return err + } + + switch v.(type) { + case []any: + type plain iceSource + return json.Unmarshal(data, (*plain)(i)) + case map[string]any: + var s sourceStats + if err := json.Unmarshal(data, &s); err != nil { + return err + } + *i = []sourceStats{s} + default: + return fmt.Errorf("invalid source data type: expected array or object") + } + + return nil +} diff --git a/src/go/plugin/go.d/modules/icecast/testdata/server_stats.json b/src/go/plugin/go.d/modules/icecast/testdata/stats_multi_source.json similarity index 100% rename from src/go/plugin/go.d/modules/icecast/testdata/server_stats.json rename to src/go/plugin/go.d/modules/icecast/testdata/stats_multi_source.json diff --git a/src/go/plugin/go.d/modules/icecast/testdata/server_stats_no_sources.json b/src/go/plugin/go.d/modules/icecast/testdata/stats_no_sources.json similarity index 100% rename from src/go/plugin/go.d/modules/icecast/testdata/server_stats_no_sources.json rename to src/go/plugin/go.d/modules/icecast/testdata/stats_no_sources.json diff --git a/src/go/plugin/go.d/modules/icecast/testdata/stats_single_source.json b/src/go/plugin/go.d/modules/icecast/testdata/stats_single_source.json new file mode 100644 index 0000000000..9d14e7d64f --- /dev/null +++ b/src/go/plugin/go.d/modules/icecast/testdata/stats_single_source.json @@ -0,0 +1,27 @@ +{ + "icestats": { + "admin": "icemaster@localhost", + "host": "localhost", + "location": "Earth", + "server_id": "Icecast 2.4.4", + "server_start": "Wed, 17 Jul 2024 11:27:40 +0300", + "server_start_iso8601": "2024-07-17T11:27:40+0300", + "source": { + "audio_info": "ice-bitrate=128;ice-channels=2;ice-samplerate=44100", + "genre": "(null)", + "ice-bitrate": 128, + "ice-channels": 2, + "ice-samplerate": 44100, + "listener_peak": 2, + "listeners": 1, + "listenurl": "http://localhost:8000/line.nsv", + "server_description": "(null)", + "server_name": "abc", + "server_type": "audio/mpeg", + "server_url": "(null)", + "stream_start": "Wed, 17 Jul 2024 12:10:20 +0300", + "stream_start_iso8601": "2024-07-17T12:10:20+0300", + "dummy": null + } + } +}