master
go 286 lines 6.76 KB
Raw
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 package icecast
4
5 import (
6 "context"
7 "net/http"
8 "net/http/httptest"
9 "os"
10 "testing"
11
12 "github.com/netdata/netdata/go/plugins/pkg/web"
13 "github.com/netdata/netdata/go/plugins/plugin/go.d/pkg/collecttest"
14
15 "github.com/stretchr/testify/assert"
16 "github.com/stretchr/testify/require"
17 )
18
19 var (
20 dataConfigJSON, _ = os.ReadFile("testdata/config.json")
21 dataConfigYAML, _ = os.ReadFile("testdata/config.yaml")
22
23 dataServerStatsMultiSource, _ = os.ReadFile("testdata/stats_multi_source.json")
24 dataServerStatsSingleSource, _ = os.ReadFile("testdata/stats_single_source.json")
25 dataServerStatsNoSources, _ = os.ReadFile("testdata/stats_no_sources.json")
26 )
27
28 func Test_testDataIsValid(t *testing.T) {
29 for name, data := range map[string][]byte{
30 "dataConfigJSON": dataConfigJSON,
31 "dataConfigYAML": dataConfigYAML,
32 "dataServerStats": dataServerStatsMultiSource,
33 "dataServerStatsSingleSource": dataServerStatsSingleSource,
34 "dataServerStatsNoSources": dataServerStatsNoSources,
35 } {
36 require.NotNil(t, data, name)
37 }
38 }
39
40 func TestCollector_ConfigurationSerialize(t *testing.T) {
41 collecttest.TestConfigurationSerialize(t, &Collector{}, dataConfigJSON, dataConfigYAML)
42 }
43
44 func TestCollector_Init(t *testing.T) {
45 tests := map[string]struct {
46 wantFail bool
47 config Config
48 }{
49 "success with default": {
50 wantFail: false,
51 config: New().Config,
52 },
53 "fail when URL not set": {
54 wantFail: true,
55 config: Config{
56 HTTPConfig: web.HTTPConfig{
57 RequestConfig: web.RequestConfig{URL: ""},
58 },
59 },
60 },
61 }
62
63 for name, test := range tests {
64 t.Run(name, func(t *testing.T) {
65 collr := New()
66 collr.Config = test.config
67
68 if test.wantFail {
69 assert.Error(t, collr.Init(context.Background()))
70 } else {
71 assert.NoError(t, collr.Init(context.Background()))
72 }
73 })
74 }
75 }
76
77 func TestCollector_Charts(t *testing.T) {
78 assert.NotNil(t, New().Charts())
79 }
80
81 func TestCollector_Check(t *testing.T) {
82 tests := map[string]struct {
83 wantFail bool
84 prepare func(t *testing.T) (*Collector, func())
85 }{
86 "success multiple sources": {
87 wantFail: false,
88 prepare: prepareCaseMultipleSources,
89 },
90 "success single source": {
91 wantFail: false,
92 prepare: prepareCaseMultipleSources,
93 },
94 "fails on no sources": {
95 wantFail: true,
96 prepare: prepareCaseNoSources,
97 },
98 "fails on unexpected json response": {
99 wantFail: true,
100 prepare: prepareCaseUnexpectedJsonResponse,
101 },
102 "fails on invalid format response": {
103 wantFail: true,
104 prepare: prepareCaseInvalidFormatResponse,
105 },
106 "fails on connection refused": {
107 wantFail: true,
108 prepare: prepareCaseConnectionRefused,
109 },
110 }
111
112 for name, test := range tests {
113 t.Run(name, func(t *testing.T) {
114 collr, cleanup := test.prepare(t)
115 defer cleanup()
116
117 if test.wantFail {
118 assert.Error(t, collr.Check(context.Background()))
119 } else {
120 assert.NoError(t, collr.Check(context.Background()))
121 }
122 })
123 }
124 }
125
126 func TestCollector_Collect(t *testing.T) {
127 tests := map[string]struct {
128 prepare func(t *testing.T) (*Collector, func())
129 wantMetrics map[string]int64
130 wantCharts int
131 }{
132 "success multiple sources": {
133 prepare: prepareCaseMultipleSources,
134 wantCharts: len(sourceChartsTmpl) * 2,
135 wantMetrics: map[string]int64{
136 "source_abc_listeners": 1,
137 "source_efg_listeners": 10,
138 },
139 },
140 "success single source": {
141 prepare: prepareCaseSingleSource,
142 wantCharts: len(sourceChartsTmpl) * 1,
143 wantMetrics: map[string]int64{
144 "source_abc_listeners": 1,
145 },
146 },
147 "fails on no sources": {
148 prepare: prepareCaseNoSources,
149 },
150 "fails on unexpected json response": {
151 prepare: prepareCaseUnexpectedJsonResponse,
152 },
153 "fails on invalid format response": {
154 prepare: prepareCaseInvalidFormatResponse,
155 },
156 "fails on connection refused": {
157 prepare: prepareCaseConnectionRefused,
158 },
159 }
160
161 for name, test := range tests {
162 t.Run(name, func(t *testing.T) {
163 collr, cleanup := test.prepare(t)
164 defer cleanup()
165
166 mx := collr.Collect(context.Background())
167
168 require.Equal(t, test.wantMetrics, mx)
169 if len(test.wantMetrics) > 0 {
170 assert.Equal(t, test.wantCharts, len(*collr.Charts()))
171 collecttest.TestMetricsHasAllChartsDims(t, collr.Charts(), mx)
172 }
173 })
174 }
175 }
176
177 func prepareCaseMultipleSources(t *testing.T) (*Collector, func()) {
178 t.Helper()
179 srv := httptest.NewServer(http.HandlerFunc(
180 func(w http.ResponseWriter, r *http.Request) {
181 switch r.URL.Path {
182 case urlPathServerStats:
183 _, _ = w.Write(dataServerStatsMultiSource)
184 default:
185 w.WriteHeader(http.StatusNotFound)
186 }
187 }))
188
189 collr := New()
190 collr.URL = srv.URL
191 require.NoError(t, collr.Init(context.Background()))
192
193 return collr, srv.Close
194 }
195
196 func prepareCaseSingleSource(t *testing.T) (*Collector, func()) {
197 t.Helper()
198 srv := httptest.NewServer(http.HandlerFunc(
199 func(w http.ResponseWriter, r *http.Request) {
200 switch r.URL.Path {
201 case urlPathServerStats:
202 _, _ = w.Write(dataServerStatsSingleSource)
203 default:
204 w.WriteHeader(http.StatusNotFound)
205 }
206 }))
207
208 collr := New()
209 collr.URL = srv.URL
210 require.NoError(t, collr.Init(context.Background()))
211
212 return collr, srv.Close
213 }
214
215 func prepareCaseNoSources(t *testing.T) (*Collector, func()) {
216 t.Helper()
217 srv := httptest.NewServer(http.HandlerFunc(
218 func(w http.ResponseWriter, r *http.Request) {
219 switch r.URL.Path {
220 case urlPathServerStats:
221 _, _ = w.Write(dataServerStatsNoSources)
222 default:
223 w.WriteHeader(http.StatusNotFound)
224 }
225 }))
226
227 collr := New()
228 collr.URL = srv.URL
229 require.NoError(t, collr.Init(context.Background()))
230
231 return collr, srv.Close
232 }
233
234 func prepareCaseUnexpectedJsonResponse(t *testing.T) (*Collector, func()) {
235 t.Helper()
236 resp := `
237 {
238 "elephant": {
239 "burn": false,
240 "mountain": true,
241 "fog": false,
242 "skin": -1561907625,
243 "burst": "anyway",
244 "shadow": 1558616893
245 },
246 "start": "ever",
247 "base": 2093056027,
248 "mission": -2007590351,
249 "victory": 999053756,
250 "die": false
251 }
252 `
253 srv := httptest.NewServer(http.HandlerFunc(
254 func(w http.ResponseWriter, r *http.Request) {
255 _, _ = w.Write([]byte(resp))
256 }))
257
258 collr := New()
259 collr.URL = srv.URL
260 require.NoError(t, collr.Init(context.Background()))
261
262 return collr, srv.Close
263 }
264
265 func prepareCaseInvalidFormatResponse(t *testing.T) (*Collector, func()) {
266 t.Helper()
267 srv := httptest.NewServer(http.HandlerFunc(
268 func(w http.ResponseWriter, r *http.Request) {
269 _, _ = w.Write([]byte("hello and\n goodbye"))
270 }))
271
272 collr := New()
273 collr.URL = srv.URL
274 require.NoError(t, collr.Init(context.Background()))
275
276 return collr, srv.Close
277 }
278
279 func prepareCaseConnectionRefused(t *testing.T) (*Collector, func()) {
280 t.Helper()
281 collr := New()
282 collr.URL = "http://127.0.0.1:65001"
283 require.NoError(t, collr.Init(context.Background()))
284
285 return collr, func() {}
286 }