master
go 285 lines 7.1 KB
Raw
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 package maxscale
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 web "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 dataVer24MaxScale, _ = os.ReadFile("testdata/v24.02.3/maxscale.json")
24 dataVer24MaxScaleThreads, _ = os.ReadFile("testdata/v24.02.3/maxscale_threads.json")
25 dataVer24Servers, _ = os.ReadFile("testdata/v24.02.3/servers.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 "dataVer24MaxScale": dataVer24MaxScale,
33 "dataVer24MaxScaleThreads": dataVer24MaxScaleThreads,
34 "dataVer24Servers": dataVer24Servers,
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_Check(t *testing.T) {
78 tests := map[string]struct {
79 wantFail bool
80 prepare func(t *testing.T) (nu *Collector, cleanup func())
81 }{
82 "success on valid response": {
83 wantFail: false,
84 prepare: caseOk,
85 },
86 "fail on unexpected JSON response": {
87 wantFail: true,
88 prepare: caseUnexpectedJsonResponse,
89 },
90 "fail on invalid data response": {
91 wantFail: true,
92 prepare: caseInvalidDataResponse,
93 },
94 "fail on connection refused": {
95 wantFail: true,
96 prepare: caseConnectionRefused,
97 },
98 "fail on 404 response": {
99 wantFail: true,
100 prepare: case404,
101 },
102 }
103
104 for name, test := range tests {
105 t.Run(name, func(t *testing.T) {
106 collr, cleanup := test.prepare(t)
107 defer cleanup()
108
109 if test.wantFail {
110 assert.Error(t, collr.Check(context.Background()))
111 } else {
112 assert.NoError(t, collr.Check(context.Background()))
113 }
114 })
115 }
116 }
117
118 func TestCollector_Charts(t *testing.T) {
119 assert.NotNil(t, New().Charts())
120 }
121
122 func TestCollector_Collect(t *testing.T) {
123 tests := map[string]struct {
124 prepare func(t *testing.T) (nu *Collector, cleanup func())
125 wantNumOfCharts int
126 wantMetrics map[string]int64
127 }{
128 "success on valid response": {
129 prepare: caseOk,
130 wantNumOfCharts: len(charts) + len(serverChartsTmpl)*1,
131 wantMetrics: map[string]int64{
132 "server_kek_connections": 0,
133 "server_kek_state_Binlog Relay": 0,
134 "server_kek_state_Down": 1,
135 "server_kek_state_Drained": 0,
136 "server_kek_state_Draining": 0,
137 "server_kek_state_Maintenance": 0,
138 "server_kek_state_Master": 0,
139 "server_kek_state_Relay Master": 0,
140 "server_kek_state_Running": 0,
141 "server_kek_state_Slave": 0,
142 "server_kek_state_Synced": 0,
143 "threads_accepts": 0,
144 "threads_current_fds": 3,
145 "threads_errors": 0,
146 "threads_hangups": 0,
147 "threads_qc_cache_evictions": 0,
148 "threads_qc_cache_hits": 0,
149 "threads_qc_cache_inserts": 0,
150 "threads_qc_cache_misses": 0,
151 "threads_reads": 68359,
152 "threads_sessions": 0,
153 "threads_state_Active": 1,
154 "threads_state_Dormant": 0,
155 "threads_state_Draining": 0,
156 "threads_total_fds": 3,
157 "threads_writes": 0,
158 "threads_zombies": 0,
159 "uptime": 61298,
160 },
161 },
162 "fail on unexpected JSON response": {
163 prepare: caseUnexpectedJsonResponse,
164 wantMetrics: nil,
165 },
166 "fail on invalid data response": {
167 prepare: caseInvalidDataResponse,
168 wantMetrics: nil,
169 },
170 "fail on connection refused": {
171 prepare: caseConnectionRefused,
172 wantMetrics: nil,
173 },
174 "fail on 404 response": {
175 prepare: case404,
176 wantMetrics: nil,
177 },
178 }
179
180 for name, test := range tests {
181 t.Run(name, func(t *testing.T) {
182 collr, cleanup := test.prepare(t)
183 defer cleanup()
184
185 _ = collr.Check(context.Background())
186
187 mx := collr.Collect(context.Background())
188
189 require.Equal(t, test.wantMetrics, mx)
190
191 if len(test.wantMetrics) > 0 {
192 assert.Equal(t, test.wantNumOfCharts, len(*collr.Charts()), "want charts")
193
194 collecttest.TestMetricsHasAllChartsDims(t, collr.Charts(), mx)
195 }
196 })
197 }
198 }
199
200 func caseOk(t *testing.T) (*Collector, func()) {
201 t.Helper()
202 srv := httptest.NewServer(http.HandlerFunc(
203 func(w http.ResponseWriter, r *http.Request) {
204 switch r.URL.Path {
205 case urlPathMaxscale:
206 _, _ = w.Write(dataVer24MaxScale)
207 case urlPathMaxscaleThreads:
208 _, _ = w.Write(dataVer24MaxScaleThreads)
209 case urlPathServers:
210 _, _ = w.Write(dataVer24Servers)
211 default:
212 w.WriteHeader(http.StatusNotFound)
213 }
214 }))
215 collr := New()
216 collr.URL = srv.URL
217 require.NoError(t, collr.Init(context.Background()))
218
219 return collr, srv.Close
220 }
221
222 func caseUnexpectedJsonResponse(t *testing.T) (*Collector, func()) {
223 t.Helper()
224 resp := `
225 {
226 "elephant": {
227 "burn": false,
228 "mountain": true,
229 "fog": false,
230 "skin": -1561907625,
231 "burst": "anyway",
232 "shadow": 1558616893
233 },
234 "start": "ever",
235 "base": 2093056027,
236 "mission": -2007590351,
237 "victory": 999053756,
238 "die": false
239 }
240 `
241 srv := httptest.NewServer(http.HandlerFunc(
242 func(w http.ResponseWriter, r *http.Request) {
243 _, _ = w.Write([]byte(resp))
244 }))
245 collr := New()
246 collr.URL = srv.URL
247 require.NoError(t, collr.Init(context.Background()))
248
249 return collr, srv.Close
250 }
251
252 func caseInvalidDataResponse(t *testing.T) (*Collector, func()) {
253 t.Helper()
254 srv := httptest.NewServer(http.HandlerFunc(
255 func(w http.ResponseWriter, r *http.Request) {
256 _, _ = w.Write([]byte("hello and\n goodbye"))
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 caseConnectionRefused(t *testing.T) (*Collector, func()) {
266 t.Helper()
267 collr := New()
268 collr.URL = "http://127.0.0.1:65001"
269 require.NoError(t, collr.Init(context.Background()))
270
271 return collr, func() {}
272 }
273
274 func case404(t *testing.T) (*Collector, func()) {
275 t.Helper()
276 srv := httptest.NewServer(http.HandlerFunc(
277 func(w http.ResponseWriter, r *http.Request) {
278 w.WriteHeader(http.StatusNotFound)
279 }))
280 collr := New()
281 collr.URL = srv.URL
282 require.NoError(t, collr.Init(context.Background()))
283
284 return collr, srv.Close
285 }