master
go 293 lines 7.78 KB
Raw
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 package uwsgi
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 dataStats, _ = os.ReadFile("testdata/stats.json")
22 dataStatsNoWorkers, _ = os.ReadFile("testdata/stats_no_workers.json")
23 )
24
25 func Test_testDataIsValid(t *testing.T) {
26 for name, data := range map[string][]byte{
27 "dataConfigJSON": dataConfigJSON,
28 "dataConfigYAML": dataConfigYAML,
29 "dataStats": dataStats,
30 "dataStatsNoWorkers": dataStatsNoWorkers,
31 } {
32 require.NotNil(t, data, name)
33 }
34 }
35
36 func TestCollector_ConfigurationSerialize(t *testing.T) {
37 collecttest.TestConfigurationSerialize(t, &Collector{}, dataConfigJSON, dataConfigYAML)
38 }
39
40 func TestCollector_Init(t *testing.T) {
41 tests := map[string]struct {
42 config Config
43 wantFail bool
44 }{
45 "success with default config": {
46 wantFail: false,
47 config: New().Config,
48 },
49 "fails if address not set": {
50 wantFail: true,
51 config: func() Config {
52 conf := New().Config
53 conf.Address = ""
54 return conf
55 }(),
56 },
57 }
58
59 for name, test := range tests {
60 t.Run(name, func(t *testing.T) {
61 collr := New()
62 collr.Config = test.config
63
64 if test.wantFail {
65 assert.Error(t, collr.Init(context.Background()))
66 } else {
67 assert.NoError(t, collr.Init(context.Background()))
68 }
69 })
70 }
71 }
72
73 func TestCollector_Cleanup(t *testing.T) {
74 tests := map[string]struct {
75 prepare func() *Collector
76 }{
77 "not initialized": {
78 prepare: func() *Collector {
79 return New()
80 },
81 },
82 "after check": {
83 prepare: func() *Collector {
84 collr := New()
85 collr.conn = prepareMockOk()
86 _ = collr.Check(context.Background())
87 return collr
88 },
89 },
90 "after collect": {
91 prepare: func() *Collector {
92 collr := New()
93 collr.conn = prepareMockOk()
94 _ = collr.Collect(context.Background())
95 return collr
96 },
97 },
98 }
99
100 for name, test := range tests {
101 t.Run(name, func(t *testing.T) {
102 collr := test.prepare()
103
104 assert.NotPanics(t, func() { collr.Cleanup(context.Background()) })
105 })
106 }
107 }
108
109 func TestCollector_Charts(t *testing.T) {
110 assert.NotNil(t, New().Charts())
111 }
112
113 func TestCollector_Check(t *testing.T) {
114 tests := map[string]struct {
115 prepareMock func() *mockUwsgiConn
116 wantFail bool
117 }{
118 "success case": {
119 wantFail: false,
120 prepareMock: prepareMockOk,
121 },
122 "success case no workers": {
123 wantFail: false,
124 prepareMock: prepareMockOkNoWorkers,
125 },
126 "unexpected response": {
127 wantFail: true,
128 prepareMock: prepareMockUnexpectedResponse,
129 },
130 "empty response": {
131 wantFail: true,
132 prepareMock: prepareMockEmptyResponse,
133 },
134 }
135
136 for name, test := range tests {
137 t.Run(name, func(t *testing.T) {
138 collr := New()
139 mock := test.prepareMock()
140 collr.conn = mock
141
142 if test.wantFail {
143 assert.Error(t, collr.Check(context.Background()))
144 } else {
145 assert.NoError(t, collr.Check(context.Background()))
146 }
147 })
148 }
149 }
150
151 func TestCollector_Collect(t *testing.T) {
152 tests := map[string]struct {
153 prepareMock func() *mockUwsgiConn
154 wantMetrics map[string]int64
155 wantCharts int
156 disconnectBeforeCleanup bool
157 disconnectAfterCleanup bool
158 }{
159 "success case": {
160 prepareMock: prepareMockOk,
161 wantCharts: len(charts) + len(workerChartsTmpl)*2,
162 disconnectBeforeCleanup: true,
163 disconnectAfterCleanup: true,
164 wantMetrics: map[string]int64{
165 "worker_1_average_request_time": 1,
166 "worker_1_delta_requests": 1,
167 "worker_1_exceptions": 1,
168 "worker_1_harakiris": 1,
169 "worker_1_memory_rss": 1,
170 "worker_1_memory_vsz": 1,
171 "worker_1_request_handling_status_accepting": 1,
172 "worker_1_request_handling_status_not_accepting": 0,
173 "worker_1_requests": 1,
174 "worker_1_respawns": 1,
175 "worker_1_status_busy": 0,
176 "worker_1_status_cheap": 0,
177 "worker_1_status_idle": 1,
178 "worker_1_status_pause": 0,
179 "worker_1_status_sig": 0,
180 "worker_1_tx": 1,
181 "worker_2_average_request_time": 1,
182 "worker_2_delta_requests": 1,
183 "worker_2_exceptions": 1,
184 "worker_2_harakiris": 1,
185 "worker_2_memory_rss": 1,
186 "worker_2_memory_vsz": 1,
187 "worker_2_request_handling_status_accepting": 1,
188 "worker_2_request_handling_status_not_accepting": 0,
189 "worker_2_requests": 1,
190 "worker_2_respawns": 1,
191 "worker_2_status_busy": 0,
192 "worker_2_status_cheap": 0,
193 "worker_2_status_idle": 1,
194 "worker_2_status_pause": 0,
195 "worker_2_status_sig": 0,
196 "worker_2_tx": 1,
197 "workers_exceptions": 2,
198 "workers_harakiris": 2,
199 "workers_requests": 2,
200 "workers_respawns": 2,
201 "workers_tx": 2,
202 },
203 },
204 "success case no workers": {
205 prepareMock: prepareMockOkNoWorkers,
206 wantCharts: len(charts),
207 wantMetrics: map[string]int64{
208 "workers_exceptions": 0,
209 "workers_harakiris": 0,
210 "workers_requests": 0,
211 "workers_respawns": 0,
212 "workers_tx": 0,
213 },
214 disconnectBeforeCleanup: true,
215 disconnectAfterCleanup: true,
216 },
217 "unexpected response": {
218 prepareMock: prepareMockUnexpectedResponse,
219 wantCharts: len(charts),
220 disconnectBeforeCleanup: true,
221 disconnectAfterCleanup: true,
222 },
223 "empty response": {
224 prepareMock: prepareMockEmptyResponse,
225 wantCharts: len(charts),
226 disconnectBeforeCleanup: true,
227 disconnectAfterCleanup: true,
228 },
229 "err on query stats": {
230 prepareMock: prepareMockErrOnQueryStats,
231 wantCharts: len(charts),
232 disconnectBeforeCleanup: true,
233 disconnectAfterCleanup: true,
234 },
235 }
236
237 for name, test := range tests {
238 t.Run(name, func(t *testing.T) {
239 collr := New()
240 mock := test.prepareMock()
241 collr.conn = mock
242
243 mx := collr.Collect(context.Background())
244
245 require.Equal(t, test.wantMetrics, mx)
246
247 if len(test.wantMetrics) > 0 {
248 collecttest.TestMetricsHasAllChartsDims(t, collr.Charts(), mx)
249 }
250 assert.Equal(t, test.wantCharts, len(*collr.Charts()), "want charts")
251 })
252 }
253 }
254
255 func prepareMockOk() *mockUwsgiConn {
256 return &mockUwsgiConn{
257 statsResponse: dataStats,
258 }
259 }
260
261 func prepareMockOkNoWorkers() *mockUwsgiConn {
262 return &mockUwsgiConn{
263 statsResponse: dataStatsNoWorkers,
264 }
265 }
266
267 func prepareMockErrOnQueryStats() *mockUwsgiConn {
268 return &mockUwsgiConn{
269 errOnQueryStats: true,
270 }
271 }
272
273 func prepareMockUnexpectedResponse() *mockUwsgiConn {
274 return &mockUwsgiConn{
275 statsResponse: []byte("Lorem ipsum dolor sit amet, consectetur adipiscing elit."),
276 }
277 }
278
279 func prepareMockEmptyResponse() *mockUwsgiConn {
280 return &mockUwsgiConn{}
281 }
282
283 type mockUwsgiConn struct {
284 errOnQueryStats bool
285 statsResponse []byte
286 }
287
288 func (m *mockUwsgiConn) queryStats() ([]byte, error) {
289 if m.errOnQueryStats {
290 return nil, errors.New("mock.queryStats() error")
291 }
292 return m.statsResponse, nil
293 }