master
go 327 lines 9.13 KB
Raw
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 package gearman
4
5 import (
6 "context"
7 "errors"
8 "os"
9 "testing"
10
11 "github.com/netdata/netdata/go/plugins/plugin/go.d/pkg/collecttest"
12
13 "github.com/stretchr/testify/assert"
14 "github.com/stretchr/testify/require"
15 )
16
17 var (
18 dataConfigJSON, _ = os.ReadFile("testdata/config.json")
19 dataConfigYAML, _ = os.ReadFile("testdata/config.yaml")
20
21 dataStatus, _ = os.ReadFile("testdata/status.txt")
22 dataPriorityStatus, _ = os.ReadFile("testdata/priority-status.txt")
23 )
24
25 func Test_testDataIsValid(t *testing.T) {
26 for name, data := range map[string][]byte{
27 "dataConfigJSON": dataConfigJSON,
28 "dataConfigYAML": dataConfigYAML,
29
30 "dataStatus": dataStatus,
31 "dataPriorityStatus": dataPriorityStatus,
32 } {
33 require.NotNil(t, data, name)
34 }
35 }
36
37 func TestCollector_ConfigurationSerialize(t *testing.T) {
38 collecttest.TestConfigurationSerialize(t, &Collector{}, dataConfigJSON, dataConfigYAML)
39 }
40
41 func TestCollector_Init(t *testing.T) {
42 tests := map[string]struct {
43 config Config
44 wantFail bool
45 }{
46 "success with default config": {
47 wantFail: false,
48 config: New().Config,
49 },
50 "fails if address not set": {
51 wantFail: true,
52 config: func() Config {
53 conf := New().Config
54 conf.Address = ""
55 return conf
56 }(),
57 },
58 }
59
60 for name, test := range tests {
61 t.Run(name, func(t *testing.T) {
62 collr := New()
63 collr.Config = test.config
64
65 if test.wantFail {
66 assert.Error(t, collr.Init(context.Background()))
67 } else {
68 assert.NoError(t, collr.Init(context.Background()))
69 }
70 })
71 }
72 }
73
74 func TestCollector_Cleanup(t *testing.T) {
75 tests := map[string]struct {
76 prepare func() *Collector
77 }{
78 "not initialized": {
79 prepare: func() *Collector {
80 return New()
81 },
82 },
83 "after check": {
84 prepare: func() *Collector {
85 collr := New()
86 collr.newConn = func(Config) gearmanConn { return prepareMockOk() }
87 _ = collr.Check(context.Background())
88 return collr
89 },
90 },
91 "after collect": {
92 prepare: func() *Collector {
93 collr := New()
94 collr.newConn = func(Config) gearmanConn { return prepareMockOk() }
95 _ = collr.Collect(context.Background())
96 return collr
97 },
98 },
99 }
100
101 for name, test := range tests {
102 t.Run(name, func(t *testing.T) {
103 collr := test.prepare()
104
105 assert.NotPanics(t, func() { collr.Cleanup(context.Background()) })
106 })
107 }
108 }
109
110 func TestCollector_Charts(t *testing.T) {
111 assert.NotNil(t, New().Charts())
112 }
113
114 func TestCollector_Check(t *testing.T) {
115 tests := map[string]struct {
116 prepareMock func() *mockGearmanConn
117 wantFail bool
118 }{
119 "success case": {
120 wantFail: false,
121 prepareMock: prepareMockOk,
122 },
123 "err on connect": {
124 wantFail: true,
125 prepareMock: prepareMockErrOnConnect,
126 },
127 "unexpected response": {
128 wantFail: true,
129 prepareMock: prepareMockUnexpectedResponse,
130 },
131 "empty response": {
132 wantFail: false,
133 prepareMock: prepareMockEmptyResponse,
134 },
135 }
136
137 for name, test := range tests {
138 t.Run(name, func(t *testing.T) {
139 collr := New()
140 mock := test.prepareMock()
141 collr.newConn = func(Config) gearmanConn { return mock }
142
143 if test.wantFail {
144 assert.Error(t, collr.Check(context.Background()))
145 } else {
146 assert.NoError(t, collr.Check(context.Background()))
147 }
148 })
149 }
150 }
151
152 func TestCollector_Collect(t *testing.T) {
153 tests := map[string]struct {
154 prepareMock func() *mockGearmanConn
155 wantMetrics map[string]int64
156 wantCharts int
157 disconnectBeforeCleanup bool
158 disconnectAfterCleanup bool
159 }{
160 "success case": {
161 prepareMock: prepareMockOk,
162 disconnectBeforeCleanup: false,
163 disconnectAfterCleanup: true,
164 wantCharts: len(summaryCharts) + len(functionStatusChartsTmpl)*4 + len(functionPriorityStatusChartsTmpl)*4,
165 wantMetrics: map[string]int64{
166 "function_generic_worker1_high_priority_jobs": 10,
167 "function_generic_worker1_jobs_queued": 4,
168 "function_generic_worker1_jobs_running": 3,
169 "function_generic_worker1_jobs_waiting": 1,
170 "function_generic_worker1_low_priority_jobs": 12,
171 "function_generic_worker1_normal_priority_jobs": 11,
172 "function_generic_worker1_workers_available": 500,
173 "function_generic_worker2_high_priority_jobs": 4,
174 "function_generic_worker2_jobs_queued": 78,
175 "function_generic_worker2_jobs_running": 78,
176 "function_generic_worker2_jobs_waiting": 0,
177 "function_generic_worker2_low_priority_jobs": 6,
178 "function_generic_worker2_normal_priority_jobs": 5,
179 "function_generic_worker2_workers_available": 500,
180 "function_generic_worker3_high_priority_jobs": 7,
181 "function_generic_worker3_jobs_queued": 2,
182 "function_generic_worker3_jobs_running": 1,
183 "function_generic_worker3_jobs_waiting": 1,
184 "function_generic_worker3_low_priority_jobs": 9,
185 "function_generic_worker3_normal_priority_jobs": 8,
186 "function_generic_worker3_workers_available": 760,
187 "function_prefix_generic_worker4_high_priority_jobs": 1,
188 "function_prefix_generic_worker4_jobs_queued": 78,
189 "function_prefix_generic_worker4_jobs_running": 78,
190 "function_prefix_generic_worker4_jobs_waiting": 0,
191 "function_prefix_generic_worker4_low_priority_jobs": 3,
192 "function_prefix_generic_worker4_normal_priority_jobs": 2,
193 "function_prefix_generic_worker4_workers_available": 500,
194 "total_high_priority_jobs": 22,
195 "total_jobs_queued": 162,
196 "total_jobs_running": 160,
197 "total_jobs_waiting": 2,
198 "total_low_priority_jobs": 30,
199 "total_normal_priority_jobs": 26,
200 "total_workers_avail": 0,
201 "total_workers_available": 2260,
202 },
203 },
204 "unexpected response": {
205 prepareMock: prepareMockUnexpectedResponse,
206 disconnectBeforeCleanup: false,
207 disconnectAfterCleanup: true,
208 },
209 "empty response": {
210 prepareMock: prepareMockEmptyResponse,
211 disconnectBeforeCleanup: false,
212 disconnectAfterCleanup: true,
213 wantCharts: len(summaryCharts),
214 wantMetrics: map[string]int64{
215 "total_high_priority_jobs": 0,
216 "total_jobs_queued": 0,
217 "total_jobs_running": 0,
218 "total_jobs_waiting": 0,
219 "total_low_priority_jobs": 0,
220 "total_normal_priority_jobs": 0,
221 "total_workers_avail": 0,
222 },
223 },
224 "err on connect": {
225 prepareMock: prepareMockErrOnConnect,
226 disconnectBeforeCleanup: false,
227 disconnectAfterCleanup: false,
228 },
229 "err on query status": {
230 prepareMock: prepareMockErrOnQueryStatus,
231 disconnectBeforeCleanup: true,
232 disconnectAfterCleanup: true,
233 },
234 }
235
236 for name, test := range tests {
237 t.Run(name, func(t *testing.T) {
238 collr := New()
239 mock := test.prepareMock()
240 collr.newConn = func(Config) gearmanConn { return mock }
241
242 mx := collr.Collect(context.Background())
243
244 require.Equal(t, test.wantMetrics, mx, "want metrics")
245
246 if len(test.wantMetrics) > 0 {
247 collecttest.TestMetricsHasAllChartsDims(t, collr.Charts(), mx)
248 assert.Equal(t, test.wantCharts, len(*collr.Charts()), "want charts")
249 }
250
251 assert.Equal(t, test.disconnectBeforeCleanup, mock.disconnectCalled, "disconnect before cleanup")
252 collr.Cleanup(context.Background())
253 assert.Equal(t, test.disconnectAfterCleanup, mock.disconnectCalled, "disconnect after cleanup")
254 })
255 }
256 }
257
258 func prepareMockOk() *mockGearmanConn {
259 return &mockGearmanConn{
260 responseStatus: dataStatus,
261 responsePriorityStatus: dataPriorityStatus,
262 }
263 }
264
265 func prepareMockErrOnConnect() *mockGearmanConn {
266 return &mockGearmanConn{
267 errOnConnect: true,
268 }
269 }
270
271 func prepareMockErrOnQueryStatus() *mockGearmanConn {
272 return &mockGearmanConn{
273 errOnQueryStatus: true,
274 }
275 }
276
277 func prepareMockUnexpectedResponse() *mockGearmanConn {
278 resp := []byte("Lorem ipsum dolor sit amet, consectetur adipiscing elit.")
279 return &mockGearmanConn{
280 responseStatus: resp,
281 responsePriorityStatus: resp,
282 }
283 }
284
285 func prepareMockEmptyResponse() *mockGearmanConn {
286 return &mockGearmanConn{
287 responseStatus: []byte("."),
288 responsePriorityStatus: []byte("."),
289 }
290 }
291
292 type mockGearmanConn struct {
293 errOnConnect bool
294
295 responseStatus []byte
296 errOnQueryStatus bool
297
298 responsePriorityStatus []byte
299 errOnQueryPriorityStatus bool
300
301 disconnectCalled bool
302 }
303
304 func (m *mockGearmanConn) connect() error {
305 if m.errOnConnect {
306 return errors.New("mock.connect() error")
307 }
308 return nil
309 }
310
311 func (m *mockGearmanConn) disconnect() {
312 m.disconnectCalled = true
313 }
314
315 func (m *mockGearmanConn) queryStatus() ([]byte, error) {
316 if m.errOnQueryStatus {
317 return nil, errors.New("mock.queryStatus() error")
318 }
319 return m.responseStatus, nil
320 }
321
322 func (m *mockGearmanConn) queryPriorityStatus() ([]byte, error) {
323 if m.errOnQueryPriorityStatus {
324 return nil, errors.New("mock.queryPriorityStatus() error")
325 }
326 return m.responsePriorityStatus, nil
327 }