master
go 296 lines 6.78 KB
Raw
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 package boinc
4
5 import (
6 "context"
7 "encoding/xml"
8 "errors"
9 "os"
10 "testing"
11
12 "github.com/netdata/netdata/go/plugins/logger"
13 "github.com/netdata/netdata/go/plugins/plugin/go.d/pkg/collecttest"
14
15 "github.com/stretchr/testify/assert"
16 "github.com/stretchr/testify/require"
17 )
18
19 var (
20 dataConfigJSON, _ = os.ReadFile("testdata/config.json")
21 dataConfigYAML, _ = os.ReadFile("testdata/config.yaml")
22
23 dataGetResults, _ = os.ReadFile("testdata/get_results.xml")
24 dataGetResultsNoTasks, _ = os.ReadFile("testdata/get_results_no_tasks.xml")
25 )
26
27 func Test_testDataIsValid(t *testing.T) {
28 for name, data := range map[string][]byte{
29 "dataConfigJSON": dataConfigJSON,
30 "dataConfigYAML": dataConfigYAML,
31 "dataGetResults": dataGetResults,
32 "dataGetResultsNoTasks": dataGetResultsNoTasks,
33 } {
34 require.NotNil(t, data, name)
35 }
36 }
37
38 func TestCollector_ConfigurationSerialize(t *testing.T) {
39 collecttest.TestConfigurationSerialize(t, &Collector{}, dataConfigJSON, dataConfigYAML)
40 }
41
42 func TestCollector_Init(t *testing.T) {
43 tests := map[string]struct {
44 config Config
45 wantFail bool
46 }{
47 "success with default config": {
48 wantFail: false,
49 config: New().Config,
50 },
51 "fails if address not set": {
52 wantFail: true,
53 config: func() Config {
54 conf := New().Config
55 conf.Address = ""
56 return conf
57 }(),
58 },
59 }
60
61 for name, test := range tests {
62 t.Run(name, func(t *testing.T) {
63 collr := New()
64 collr.Config = test.config
65
66 if test.wantFail {
67 assert.Error(t, collr.Init(context.Background()))
68 } else {
69 assert.NoError(t, collr.Init(context.Background()))
70 }
71 })
72 }
73 }
74
75 func TestCollector_Cleanup(t *testing.T) {
76 tests := map[string]struct {
77 prepare func() *Collector
78 }{
79 "not initialized": {
80 prepare: func() *Collector {
81 return New()
82 },
83 },
84 "after check": {
85 prepare: func() *Collector {
86 collr := New()
87 collr.newConn = func(Config, *logger.Logger) boincConn { return prepareMockOk() }
88 _ = collr.Check(context.Background())
89 return collr
90 },
91 },
92 "after collect": {
93 prepare: func() *Collector {
94 collr := New()
95 collr.newConn = func(Config, *logger.Logger) boincConn { return prepareMockOk() }
96 _ = collr.Collect(context.Background())
97 return collr
98 },
99 },
100 }
101
102 for name, test := range tests {
103 t.Run(name, func(t *testing.T) {
104 collr := test.prepare()
105
106 assert.NotPanics(t, func() { collr.Cleanup(context.Background()) })
107 })
108 }
109 }
110
111 func TestCollector_Charts(t *testing.T) {
112 assert.NotNil(t, New().Charts())
113 }
114
115 func TestCollector_Check(t *testing.T) {
116 tests := map[string]struct {
117 prepareMock func() *mockBoincConn
118 wantFail bool
119 }{
120 "success case": {
121 wantFail: false,
122 prepareMock: prepareMockOk,
123 },
124 "err on connect": {
125 wantFail: true,
126 prepareMock: prepareMockErrOnConnect,
127 },
128 }
129
130 for name, test := range tests {
131 t.Run(name, func(t *testing.T) {
132 collr := New()
133 mock := test.prepareMock()
134 collr.newConn = func(Config, *logger.Logger) boincConn { return mock }
135
136 if test.wantFail {
137 assert.Error(t, collr.Check(context.Background()))
138 } else {
139 assert.NoError(t, collr.Check(context.Background()))
140 }
141 })
142 }
143 }
144
145 func TestCollector_Collect(t *testing.T) {
146 tests := map[string]struct {
147 prepareMock func() *mockBoincConn
148 wantMetrics map[string]int64
149 disconnectBeforeCleanup bool
150 disconnectAfterCleanup bool
151 }{
152 "success case with tasks": {
153 prepareMock: prepareMockOk,
154 disconnectBeforeCleanup: false,
155 disconnectAfterCleanup: true,
156 wantMetrics: map[string]int64{
157 "abort_pending": 0,
158 "aborted": 0,
159 "active": 14,
160 "compute_error": 0,
161 "copy_pending": 0,
162 "executing": 11,
163 "files_downloaded": 110,
164 "files_downloading": 0,
165 "files_uploaded": 8,
166 "files_uploading": 0,
167 "new": 0,
168 "preempted": 3,
169 "quit_pending": 0,
170 "scheduled": 11,
171 "suspended": 3,
172 "total": 118,
173 "uninitialized": 0,
174 "upload_failed": 0,
175 },
176 },
177 "success case no tasks": {
178 prepareMock: prepareMockOkNoTasks,
179 disconnectBeforeCleanup: false,
180 disconnectAfterCleanup: true,
181 wantMetrics: map[string]int64{
182 "abort_pending": 0,
183 "aborted": 0,
184 "active": 0,
185 "compute_error": 0,
186 "copy_pending": 0,
187 "executing": 0,
188 "files_downloaded": 0,
189 "files_downloading": 0,
190 "files_uploaded": 0,
191 "files_uploading": 0,
192 "new": 0,
193 "preempted": 0,
194 "quit_pending": 0,
195 "scheduled": 0,
196 "suspended": 0,
197 "total": 0,
198 "uninitialized": 0,
199 "upload_failed": 0,
200 },
201 },
202 "err on connect": {
203 prepareMock: prepareMockErrOnConnect,
204 disconnectBeforeCleanup: false,
205 disconnectAfterCleanup: false,
206 },
207 "err on get results": {
208 prepareMock: prepareMockErrOnGetResults,
209 disconnectBeforeCleanup: true,
210 disconnectAfterCleanup: true,
211 },
212 }
213
214 for name, test := range tests {
215 t.Run(name, func(t *testing.T) {
216 collr := New()
217 mock := test.prepareMock()
218 collr.newConn = func(Config, *logger.Logger) boincConn { return mock }
219
220 mx := collr.Collect(context.Background())
221
222 require.Equal(t, test.wantMetrics, mx)
223
224 if len(test.wantMetrics) > 0 {
225 collecttest.TestMetricsHasAllChartsDims(t, collr.Charts(), mx)
226 }
227
228 assert.Equal(t, test.disconnectBeforeCleanup, mock.disconnectCalled, "disconnect before cleanup")
229 collr.Cleanup(context.Background())
230 assert.Equal(t, test.disconnectAfterCleanup, mock.disconnectCalled, "disconnect after cleanup")
231 })
232 }
233 }
234
235 func prepareMockOk() *mockBoincConn {
236 return &mockBoincConn{
237 getResultsResp: dataGetResults,
238 }
239 }
240
241 func prepareMockOkNoTasks() *mockBoincConn {
242 return &mockBoincConn{
243 getResultsResp: dataGetResultsNoTasks,
244 }
245 }
246
247 func prepareMockErrOnConnect() *mockBoincConn {
248 return &mockBoincConn{
249 errOnConnect: true,
250 }
251 }
252
253 func prepareMockErrOnGetResults() *mockBoincConn {
254 return &mockBoincConn{
255 errOnGetResults: true,
256 }
257 }
258
259 type mockBoincConn struct {
260 errOnConnect bool
261
262 errOnGetResults bool
263 getResultsResp []byte
264
265 authCalled bool
266 disconnectCalled bool
267 }
268
269 func (m *mockBoincConn) connect() error {
270 if m.errOnConnect {
271 return errors.New("mock.connect() error")
272 }
273 return nil
274 }
275
276 func (m *mockBoincConn) disconnect() {
277 m.disconnectCalled = true
278 }
279
280 func (m *mockBoincConn) authenticate() error {
281 m.authCalled = true
282 return nil
283 }
284
285 func (m *mockBoincConn) getResults() ([]boincReplyResult, error) {
286 if m.errOnGetResults {
287 return nil, errors.New("mock.getResults() error")
288 }
289
290 var resp boincReply
291 if err := xml.Unmarshal(m.getResultsResp, &resp); err != nil {
292 return nil, err
293 }
294
295 return resp.Results, nil
296 }