master
go 389 lines 12.7 KB
Raw
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 package nats
4
5 import (
6 "context"
7 "net/http"
8 "net/http/httptest"
9 "os"
10 "testing"
11
12 "github.com/stretchr/testify/assert"
13 "github.com/stretchr/testify/require"
14
15 "github.com/netdata/netdata/go/plugins/pkg/web"
16 "github.com/netdata/netdata/go/plugins/plugin/go.d/pkg/collecttest"
17 )
18
19 var (
20 dataConfigJSON, _ = os.ReadFile("testdata/config.json")
21 dataConfigYAML, _ = os.ReadFile("testdata/config.yaml")
22
23 dataVer210HealthzOk, _ = os.ReadFile("testdata/v2.10.24/healthz-ok.json")
24 dataVer210Varz, _ = os.ReadFile("testdata/v2.10.24/varz.json")
25 dataVer210Accstatz, _ = os.ReadFile("testdata/v2.10.24/accstatz.json")
26 dataVer210Routez, _ = os.ReadFile("testdata/v2.10.24/routez.json")
27 dataVer210Gatewayz, _ = os.ReadFile("testdata/v2.10.24/gatewayz.json")
28 dataVer210Leafz, _ = os.ReadFile("testdata/v2.10.24/leafz.json")
29 dataVer210Jsz, _ = os.ReadFile("testdata/v2.10.24/jsz.json")
30 )
31
32 func Test_testDataIsValid(t *testing.T) {
33 for name, data := range map[string][]byte{
34 "dataConfigJSON": dataConfigJSON,
35 "dataConfigYAML": dataConfigYAML,
36 "dataVer210HealthzOk": dataVer210HealthzOk,
37 "dataVer210Varz": dataVer210Varz,
38 "dataVer210Accstatz": dataVer210Accstatz,
39 "dataVer210Routez": dataVer210Routez,
40 "dataVer210Gatewayz": dataVer210Gatewayz,
41 "dataVer210Leafz": dataVer210Leafz,
42 "dataVer210Jsz": dataVer210Jsz,
43 } {
44 require.NotNil(t, data, name)
45 }
46 }
47
48 func TestCollector_ConfigurationSerialize(t *testing.T) {
49 collecttest.TestConfigurationSerialize(t, &Collector{}, dataConfigJSON, dataConfigYAML)
50 }
51
52 func TestCollector_Init(t *testing.T) {
53 tests := map[string]struct {
54 wantFail bool
55 config Config
56 }{
57 "success with default": {
58 wantFail: false,
59 config: New().Config,
60 },
61 "fail when URL not set": {
62 wantFail: true,
63 config: Config{
64 HTTPConfig: web.HTTPConfig{
65 RequestConfig: web.RequestConfig{URL: ""},
66 },
67 },
68 },
69 }
70
71 for name, test := range tests {
72 t.Run(name, func(t *testing.T) {
73 collr := New()
74 collr.Config = test.config
75
76 if test.wantFail {
77 assert.Error(t, collr.Init(context.Background()))
78 } else {
79 assert.NoError(t, collr.Init(context.Background()))
80 }
81 })
82 }
83 }
84
85 func TestCollector_Check(t *testing.T) {
86 tests := map[string]struct {
87 wantFail bool
88 prepare func(t *testing.T) (nu *Collector, cleanup func())
89 }{
90 "success on valid response": {
91 wantFail: false,
92 prepare: caseOk,
93 },
94 "fail on unexpected JSON response": {
95 wantFail: true,
96 prepare: caseUnexpectedJsonResponse,
97 },
98 "fail on invalid data response": {
99 wantFail: true,
100 prepare: caseInvalidDataResponse,
101 },
102 "fail on connection refused": {
103 wantFail: true,
104 prepare: caseConnectionRefused,
105 },
106 "fail on 404 response": {
107 wantFail: true,
108 prepare: case404,
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_Charts(t *testing.T) {
127 assert.NotNil(t, New().Charts())
128 }
129
130 func TestCollector_Collect(t *testing.T) {
131 tests := map[string]struct {
132 prepare func(t *testing.T) (nu *Collector, cleanup func())
133 wantNumOfCharts int
134 wantMetrics map[string]int64
135 }{
136 "success on valid response": {
137 prepare: caseOk,
138 wantNumOfCharts: len(*serverCharts()) +
139 len(accountChartsTmpl)*3 +
140 len(routeChartsTmpl)*1 +
141 len(gatewayConnChartsTmpl)*5 +
142 len(leafConnChartsTmpl)*1,
143 wantMetrics: map[string]int64{
144 "accstatz_acc_$G_conns": 0,
145 "accstatz_acc_$G_leaf_nodes": 0,
146 "accstatz_acc_$G_num_subs": 5,
147 "accstatz_acc_$G_received_bytes": 0,
148 "accstatz_acc_$G_received_msgs": 0,
149 "accstatz_acc_$G_sent_bytes": 0,
150 "accstatz_acc_$G_sent_msgs": 0,
151 "accstatz_acc_$G_slow_consumers": 0,
152 "accstatz_acc_$G_total_conns": 0,
153 "accstatz_acc_$SYS_conns": 0,
154 "accstatz_acc_$SYS_leaf_nodes": 0,
155 "accstatz_acc_$SYS_num_subs": 220,
156 "accstatz_acc_$SYS_received_bytes": 0,
157 "accstatz_acc_$SYS_received_msgs": 0,
158 "accstatz_acc_$SYS_sent_bytes": 0,
159 "accstatz_acc_$SYS_sent_msgs": 0,
160 "accstatz_acc_$SYS_slow_consumers": 0,
161 "accstatz_acc_$SYS_total_conns": 0,
162 "accstatz_acc_default_conns": 44,
163 "accstatz_acc_default_leaf_nodes": 0,
164 "accstatz_acc_default_num_subs": 1133,
165 "accstatz_acc_default_received_bytes": 62023455,
166 "accstatz_acc_default_received_msgs": 916392,
167 "accstatz_acc_default_sent_bytes": 529749990,
168 "accstatz_acc_default_sent_msgs": 2546732,
169 "accstatz_acc_default_slow_consumers": 1,
170 "accstatz_acc_default_total_conns": 44,
171 "gatewayz_inbound_gw_region2_cid_9_in_bytes": 0,
172 "gatewayz_inbound_gw_region2_cid_9_in_msgs": 0,
173 "gatewayz_inbound_gw_region2_cid_9_num_subs": 0,
174 "gatewayz_inbound_gw_region2_cid_9_out_bytes": 0,
175 "gatewayz_inbound_gw_region2_cid_9_out_msgs": 0,
176 "gatewayz_inbound_gw_region2_cid_9_uptime": 6,
177 "gatewayz_inbound_gw_region3_cid_4_in_bytes": 0,
178 "gatewayz_inbound_gw_region3_cid_4_in_msgs": 0,
179 "gatewayz_inbound_gw_region3_cid_4_num_subs": 0,
180 "gatewayz_inbound_gw_region3_cid_4_out_bytes": 0,
181 "gatewayz_inbound_gw_region3_cid_4_out_msgs": 0,
182 "gatewayz_inbound_gw_region3_cid_4_uptime": 6,
183 "gatewayz_inbound_gw_region3_cid_8_in_bytes": 0,
184 "gatewayz_inbound_gw_region3_cid_8_in_msgs": 0,
185 "gatewayz_inbound_gw_region3_cid_8_num_subs": 0,
186 "gatewayz_inbound_gw_region3_cid_8_out_bytes": 0,
187 "gatewayz_inbound_gw_region3_cid_8_out_msgs": 0,
188 "gatewayz_inbound_gw_region3_cid_8_uptime": 6,
189 "gatewayz_outbound_gw_region2_cid_7_in_bytes": 0,
190 "gatewayz_outbound_gw_region2_cid_7_in_msgs": 0,
191 "gatewayz_outbound_gw_region2_cid_7_num_subs": 0,
192 "gatewayz_outbound_gw_region2_cid_7_out_bytes": 0,
193 "gatewayz_outbound_gw_region2_cid_7_out_msgs": 0,
194 "gatewayz_outbound_gw_region2_cid_7_uptime": 6,
195 "gatewayz_outbound_gw_region3_cid_5_in_bytes": 0,
196 "gatewayz_outbound_gw_region3_cid_5_in_msgs": 0,
197 "gatewayz_outbound_gw_region3_cid_5_num_subs": 0,
198 "gatewayz_outbound_gw_region3_cid_5_out_bytes": 0,
199 "gatewayz_outbound_gw_region3_cid_5_out_msgs": 0,
200 "gatewayz_outbound_gw_region3_cid_5_uptime": 6,
201 "jsz_api_errors": 588,
202 "jsz_api_inflight": 0,
203 "jsz_api_total": 936916,
204 "jsz_bytes": 114419224,
205 "jsz_consumers": 9,
206 "jsz_disabled": 0,
207 "jsz_enabled": 1,
208 "jsz_memory_used": 128,
209 "jsz_messages": 5670,
210 "jsz_store_used": 114419224,
211 "jsz_streams": 198,
212 "leafz_leaf__$G_127.0.0.1_6223_in_bytes": 0,
213 "leafz_leaf__$G_127.0.0.1_6223_in_msgs": 0,
214 "leafz_leaf__$G_127.0.0.1_6223_num_subs": 1,
215 "leafz_leaf__$G_127.0.0.1_6223_out_bytes": 1280000,
216 "leafz_leaf__$G_127.0.0.1_6223_out_msgs": 10000,
217 "leafz_leaf__$G_127.0.0.1_6223_rtt": 200,
218 "routez_route_id_1_in_bytes": 4,
219 "routez_route_id_1_in_msgs": 1,
220 "routez_route_id_1_num_subs": 1,
221 "routez_route_id_1_out_bytes": 4,
222 "routez_route_id_1_out_msgs": 1,
223 "varz_http_endpoint_/_req": 5710,
224 "varz_http_endpoint_/accountz_req": 2201,
225 "varz_http_endpoint_/accstatz_req": 6,
226 "varz_http_endpoint_/connz_req": 3649,
227 "varz_http_endpoint_/gatewayz_req": 2204,
228 "varz_http_endpoint_/healthz_req": 3430,
229 "varz_http_endpoint_/ipqueuesz_req": 0,
230 "varz_http_endpoint_/jsz_req": 2958,
231 "varz_http_endpoint_/leafz_req": 9,
232 "varz_http_endpoint_/raftz_req": 0,
233 "varz_http_endpoint_/routez_req": 2202,
234 "varz_http_endpoint_/stacksz_req": 0,
235 "varz_http_endpoint_/subsz_req": 4412,
236 "varz_http_endpoint_/varz_req": 7114,
237 "varz_srv_connections": 44,
238 "varz_srv_cpu": 10,
239 "varz_srv_healthz_status_error": 0,
240 "varz_srv_healthz_status_ok": 1,
241 "varz_srv_in_bytes": 62024985,
242 "varz_srv_in_msgs": 916475,
243 "varz_srv_mem": 95731712,
244 "varz_srv_out_bytes": 529775656,
245 "varz_srv_out_msgs": 2546840,
246 "varz_srv_remotes": 0,
247 "varz_srv_routes": 0,
248 "varz_srv_slow_consumers": 1,
249 "varz_srv_subscriptions": 1358,
250 "varz_srv_total_connections": 74932,
251 "varz_srv_uptime": 339394,
252 },
253 },
254 "fail on unexpected JSON response": {
255 prepare: caseUnexpectedJsonResponse,
256 wantMetrics: nil,
257 },
258 "fail on invalid data response": {
259 prepare: caseInvalidDataResponse,
260 wantMetrics: nil,
261 },
262 "fail on connection refused": {
263 prepare: caseConnectionRefused,
264 wantMetrics: nil,
265 },
266 "fail on 404 response": {
267 prepare: case404,
268 wantMetrics: nil,
269 },
270 }
271
272 for name, test := range tests {
273 t.Run(name, func(t *testing.T) {
274 collr, cleanup := test.prepare(t)
275 defer cleanup()
276
277 _ = collr.Check(context.Background())
278
279 mx := collr.Collect(context.Background())
280
281 require.Equal(t, test.wantMetrics, mx)
282
283 if len(test.wantMetrics) > 0 {
284 assert.Equal(t, test.wantNumOfCharts, len(*collr.Charts()), "want charts")
285
286 collecttest.TestMetricsHasAllChartsDims(t, collr.Charts(), mx)
287 }
288 })
289 }
290 }
291
292 func caseOk(t *testing.T) (*Collector, func()) {
293 t.Helper()
294 srv := httptest.NewServer(http.HandlerFunc(
295 func(w http.ResponseWriter, r *http.Request) {
296 switch r.URL.Path {
297 case urlPathHealthz:
298 _, _ = w.Write(dataVer210HealthzOk)
299 case urlPathVarz:
300 _, _ = w.Write(dataVer210Varz)
301 case urlPathAccstatz:
302 if r.URL.RawQuery != urlQueryAccstatz {
303 w.WriteHeader(http.StatusNotFound)
304 return
305 }
306 _, _ = w.Write(dataVer210Accstatz)
307 case urlPathRoutez:
308 _, _ = w.Write(dataVer210Routez)
309 case urlPathGatewayz:
310 _, _ = w.Write(dataVer210Gatewayz)
311 case urlPathLeafz:
312 _, _ = w.Write(dataVer210Leafz)
313 case urlPathJsz:
314 _, _ = w.Write(dataVer210Jsz)
315 default:
316 w.WriteHeader(http.StatusNotFound)
317 }
318 }))
319 collr := New()
320 collr.URL = srv.URL
321 require.NoError(t, collr.Init(context.Background()))
322
323 return collr, srv.Close
324 }
325
326 func caseUnexpectedJsonResponse(t *testing.T) (*Collector, func()) {
327 t.Helper()
328 resp := `
329 {
330 "elephant": {
331 "burn": false,
332 "mountain": true,
333 "fog": false,
334 "skin": -1561907625,
335 "burst": "anyway",
336 "shadow": 1558616893
337 },
338 "start": "ever",
339 "base": 2093056027,
340 "mission": -2007590351,
341 "victory": 999053756,
342 "die": false
343 }
344 `
345 srv := httptest.NewServer(http.HandlerFunc(
346 func(w http.ResponseWriter, r *http.Request) {
347 _, _ = w.Write([]byte(resp))
348 }))
349 collr := New()
350 collr.URL = srv.URL
351 require.NoError(t, collr.Init(context.Background()))
352
353 return collr, srv.Close
354 }
355
356 func caseInvalidDataResponse(t *testing.T) (*Collector, func()) {
357 t.Helper()
358 srv := httptest.NewServer(http.HandlerFunc(
359 func(w http.ResponseWriter, r *http.Request) {
360 _, _ = w.Write([]byte("hello and\n goodbye"))
361 }))
362 collr := New()
363 collr.URL = srv.URL
364 require.NoError(t, collr.Init(context.Background()))
365
366 return collr, srv.Close
367 }
368
369 func caseConnectionRefused(t *testing.T) (*Collector, func()) {
370 t.Helper()
371 collr := New()
372 collr.URL = "http://127.0.0.1:65001"
373 require.NoError(t, collr.Init(context.Background()))
374
375 return collr, func() {}
376 }
377
378 func case404(t *testing.T) (*Collector, func()) {
379 t.Helper()
380 srv := httptest.NewServer(http.HandlerFunc(
381 func(w http.ResponseWriter, r *http.Request) {
382 w.WriteHeader(http.StatusNotFound)
383 }))
384 collr := New()
385 collr.URL = srv.URL
386 require.NoError(t, collr.Init(context.Background()))
387
388 return collr, srv.Close
389 }