master
go 352 lines 8.17 KB
Raw
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 package spigotmc
4
5 import (
6 "context"
7 "errors"
8 "os"
9 "testing"
10
11 "github.com/stretchr/testify/assert"
12 "github.com/stretchr/testify/require"
13
14 "github.com/netdata/netdata/go/plugins/plugin/go.d/pkg/collecttest"
15 )
16
17 var (
18 dataConfigJSON, _ = os.ReadFile("testdata/config.json")
19 dataConfigYAML, _ = os.ReadFile("testdata/config.yaml")
20
21 dataRespTsp = `
22 §6TPS from last 1m, 5m, 15m: §a*20.0, §a*20.0, §a*20.0
23 §6Current Memory Usage: §a332/392 mb (Max: 6008 mb)
24 `
25 dataRespListClean = `There are 4 of a max 50 players online: player1, player2, player3, player4`
26 dataRespListDoubleS = `There are 4 of a max 50 players online: player1, player2, player3, player4`
27 dataRespListDoubleSWithHidden = `§6There are §c3§6/§c1§6 out of maximum §c50§6 players online.`
28 dataRespListDoubleSNonEng = `§6当前有 §c4§6 个玩家在线,最大在线人数为 §c50§6 个玩家.`
29 )
30
31 func Test_testDataIsValid(t *testing.T) {
32 for name, data := range map[string][]byte{
33 "dataConfigJSON": dataConfigJSON,
34 "dataConfigYAML": dataConfigYAML,
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 config Config
47 wantFail bool
48 }{
49 "fails with default config": {
50 wantFail: true,
51 config: New().Config,
52 },
53 "fails if address not set": {
54 wantFail: true,
55 config: func() Config {
56 conf := New().Config
57 conf.Address = ""
58 conf.Password = "pass"
59 return conf
60 }(),
61 },
62 }
63
64 for name, test := range tests {
65 t.Run(name, func(t *testing.T) {
66 collr := New()
67 collr.Config = test.config
68
69 if test.wantFail {
70 assert.Error(t, collr.Init(context.Background()))
71 } else {
72 assert.NoError(t, collr.Init(context.Background()))
73 }
74 })
75 }
76 }
77
78 func TestCollector_Cleanup(t *testing.T) {
79 tests := map[string]struct {
80 prepare func() *Collector
81 }{
82 "not initialized": {
83 prepare: func() *Collector {
84 return New()
85 },
86 },
87 "after check": {
88 prepare: func() *Collector {
89 collr := New()
90 collr.newConn = func(Config) rconConn { return prepareMockOk() }
91 _ = collr.Check(context.Background())
92 return collr
93 },
94 },
95 "after collect": {
96 prepare: func() *Collector {
97 collr := New()
98 collr.newConn = func(Config) rconConn { return prepareMockOk() }
99 _ = collr.Collect(context.Background())
100 return collr
101 },
102 },
103 }
104
105 for name, test := range tests {
106 t.Run(name, func(t *testing.T) {
107 collr := test.prepare()
108
109 assert.NotPanics(t, func() { collr.Cleanup(context.Background()) })
110 })
111 }
112 }
113
114 func TestCollector_Charts(t *testing.T) {
115 assert.NotNil(t, New().Charts())
116 }
117
118 func TestCollector_Check(t *testing.T) {
119 tests := map[string]struct {
120 prepareMock func() *mockRcon
121 wantFail bool
122 }{
123 "success case": {
124 wantFail: false,
125 prepareMock: prepareMockOk,
126 },
127 "err on connect": {
128 wantFail: true,
129 prepareMock: prepareMockErrOnConnect,
130 },
131 "unexpected response": {
132 wantFail: true,
133 prepareMock: prepareMockUnexpectedResponse,
134 },
135 "empty response": {
136 wantFail: true,
137 prepareMock: prepareMockEmptyResponse,
138 },
139 }
140
141 for name, test := range tests {
142 t.Run(name, func(t *testing.T) {
143 collr := New()
144 mock := test.prepareMock()
145 collr.newConn = func(Config) rconConn { return mock }
146
147 if test.wantFail {
148 assert.Error(t, collr.Check(context.Background()))
149 } else {
150 assert.NoError(t, collr.Check(context.Background()))
151 }
152 })
153 }
154 }
155
156 func TestCollector_Collect(t *testing.T) {
157 tests := map[string]struct {
158 prepareMock func() *mockRcon
159 wantMetrics map[string]int64
160 disconnectBeforeCleanup bool
161 disconnectAfterCleanup bool
162 }{
163 "success case: clean": {
164 prepareMock: prepareMockOkClean,
165 disconnectBeforeCleanup: false,
166 disconnectAfterCleanup: true,
167 wantMetrics: map[string]int64{
168 "mem_alloc": 411041792,
169 "mem_max": 6299844608,
170 "mem_used": 348127232,
171 "players": 4,
172 "tps_15min": 2000,
173 "tps_1min": 2000,
174 "tps_5min": 2000,
175 },
176 },
177 "success case: double s": {
178 prepareMock: prepareMockOk,
179 disconnectBeforeCleanup: false,
180 disconnectAfterCleanup: true,
181 wantMetrics: map[string]int64{
182 "mem_alloc": 411041792,
183 "mem_max": 6299844608,
184 "mem_used": 348127232,
185 "players": 4,
186 "tps_15min": 2000,
187 "tps_1min": 2000,
188 "tps_5min": 2000,
189 },
190 },
191 "success case: double s with hidden": {
192 prepareMock: prepareMockOkSWithHidden,
193 disconnectBeforeCleanup: false,
194 disconnectAfterCleanup: true,
195 wantMetrics: map[string]int64{
196 "mem_alloc": 411041792,
197 "mem_max": 6299844608,
198 "mem_used": 348127232,
199 "players": 4,
200 "tps_15min": 2000,
201 "tps_1min": 2000,
202 "tps_5min": 2000,
203 },
204 },
205 "success case: non english": {
206 prepareMock: prepareMockOkSNonEng,
207 disconnectBeforeCleanup: false,
208 disconnectAfterCleanup: true,
209 wantMetrics: map[string]int64{
210 "mem_alloc": 411041792,
211 "mem_max": 6299844608,
212 "mem_used": 348127232,
213 "players": 4,
214 "tps_15min": 2000,
215 "tps_1min": 2000,
216 "tps_5min": 2000,
217 },
218 },
219 "unexpected response": {
220 prepareMock: prepareMockUnexpectedResponse,
221 disconnectBeforeCleanup: true,
222 disconnectAfterCleanup: true,
223 },
224 "empty response": {
225 prepareMock: prepareMockEmptyResponse,
226 disconnectBeforeCleanup: true,
227 disconnectAfterCleanup: true,
228 wantMetrics: nil,
229 },
230 "err on connect": {
231 prepareMock: prepareMockErrOnConnect,
232 disconnectBeforeCleanup: false,
233 disconnectAfterCleanup: false,
234 },
235 "err on query status": {
236 prepareMock: prepareMockErrOnQuery,
237 disconnectBeforeCleanup: true,
238 disconnectAfterCleanup: true,
239 },
240 }
241
242 for name, test := range tests {
243 t.Run(name, func(t *testing.T) {
244 collr := New()
245 mock := test.prepareMock()
246 collr.newConn = func(Config) rconConn { return mock }
247
248 mx := collr.Collect(context.Background())
249
250 require.Equal(t, test.wantMetrics, mx, "want metrics")
251
252 if len(test.wantMetrics) > 0 {
253 collecttest.TestMetricsHasAllChartsDims(t, collr.Charts(), mx)
254 assert.Equal(t, len(charts), len(*collr.Charts()), "want charts")
255 }
256
257 assert.Equal(t, test.disconnectBeforeCleanup, mock.disconnectCalled, "disconnect before cleanup")
258 collr.Cleanup(context.Background())
259 assert.Equal(t, test.disconnectAfterCleanup, mock.disconnectCalled, "disconnect after cleanup")
260 })
261 }
262 }
263
264 func prepareMockOkClean() *mockRcon {
265 return &mockRcon{
266 responseTps: dataRespTsp,
267 responseList: dataRespListClean,
268 }
269 }
270
271 func prepareMockOk() *mockRcon {
272 return &mockRcon{
273 responseTps: dataRespTsp,
274 responseList: dataRespListDoubleS,
275 }
276 }
277
278 func prepareMockOkSWithHidden() *mockRcon {
279 return &mockRcon{
280 responseTps: dataRespTsp,
281 responseList: dataRespListDoubleSWithHidden,
282 }
283 }
284
285 func prepareMockOkSNonEng() *mockRcon {
286 return &mockRcon{
287 responseTps: dataRespTsp,
288 responseList: dataRespListDoubleSNonEng,
289 }
290 }
291
292 func prepareMockErrOnConnect() *mockRcon {
293 return &mockRcon{
294 errOnConnect: true,
295 }
296 }
297
298 func prepareMockErrOnQuery() *mockRcon {
299 return &mockRcon{
300 errOnQuery: true,
301 }
302 }
303
304 func prepareMockUnexpectedResponse() *mockRcon {
305 resp := "Lorem ipsum dolor sit amet, consectetur adipiscing elit."
306
307 return &mockRcon{
308 responseTps: resp,
309 responseList: resp,
310 }
311 }
312
313 func prepareMockEmptyResponse() *mockRcon {
314 return &mockRcon{
315 responseTps: "",
316 responseList: "",
317 }
318 }
319
320 type mockRcon struct {
321 errOnConnect bool
322 responseTps string
323 responseList string
324 errOnQuery bool
325 disconnectCalled bool
326 }
327
328 func (m *mockRcon) connect() error {
329 if m.errOnConnect {
330 return errors.New("mock.connect() error")
331 }
332 return nil
333 }
334
335 func (m *mockRcon) disconnect() error {
336 m.disconnectCalled = true
337 return nil
338 }
339
340 func (m *mockRcon) queryTps() (string, error) {
341 if m.errOnQuery {
342 return "", errors.New("mock.queryTps() error")
343 }
344 return m.responseTps, nil
345 }
346
347 func (m *mockRcon) queryList() (string, error) {
348 if m.errOnQuery {
349 return "", errors.New("mock.queryList() error")
350 }
351 return m.responseList, nil
352 }