master
go 339 lines 8.86 KB
Raw
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 package adaptecraid
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 dataLogicalDevicesOld, _ = os.ReadFile("testdata/getconfig-ld-old.txt")
22 dataPhysicalDevicesOld, _ = os.ReadFile("testdata/getconfig-pd-old.txt")
23 dataLogicalDevicesCurrent, _ = os.ReadFile("testdata/getconfig-ld-current.txt")
24 dataPhysicalDevicesCurrent, _ = os.ReadFile("testdata/getconfig-pd-current.txt")
25 dataPhysicalDevicesWithEnclosure, _ = os.ReadFile("testdata/getconfig-pd-with-enclosure.txt")
26 )
27
28 func Test_testDataIsValid(t *testing.T) {
29 for name, data := range map[string][]byte{
30 "dataConfigJSON": dataConfigJSON,
31 "dataConfigYAML": dataConfigYAML,
32
33 "dataLogicalDevicesOld": dataLogicalDevicesOld,
34 "dataPhysicalDevicesOld": dataPhysicalDevicesOld,
35 "dataLogicalDevicesCurrent": dataLogicalDevicesCurrent,
36 "dataPhysicalDevicesCurrent": dataPhysicalDevicesCurrent,
37 "dataPhysicalDevicesWithEnclosure": dataPhysicalDevicesWithEnclosure,
38 } {
39 require.NotNil(t, data, name)
40 }
41 }
42
43 func TestCollector_ConfigurationSerialize(t *testing.T) {
44 collecttest.TestConfigurationSerialize(t, &Collector{}, dataConfigJSON, dataConfigYAML)
45 }
46
47 func TestCollector_Init(t *testing.T) {
48 tests := map[string]struct {
49 config Config
50 wantFail bool
51 }{
52 "success with default config": {
53 wantFail: false,
54 config: New().Config,
55 },
56 }
57
58 for name, test := range tests {
59 t.Run(name, func(t *testing.T) {
60 collr := New()
61
62 if test.wantFail {
63 assert.Error(t, collr.Init(context.Background()))
64 } else {
65 assert.NoError(t, collr.Init(context.Background()))
66 }
67 })
68 }
69 }
70
71 func TestCollector_Cleanup(t *testing.T) {
72 tests := map[string]struct {
73 prepare func() *Collector
74 }{
75 "not initialized exec": {
76 prepare: func() *Collector {
77 return New()
78 },
79 },
80 "after check": {
81 prepare: func() *Collector {
82 collr := New()
83 collr.exec = prepareMockOkCurrent()
84 _ = collr.Check(context.Background())
85 return collr
86 },
87 },
88 "after collect": {
89 prepare: func() *Collector {
90 collr := New()
91 collr.exec = prepareMockOkCurrent()
92 _ = collr.Collect(context.Background())
93 return collr
94 },
95 },
96 }
97
98 for name, test := range tests {
99 t.Run(name, func(t *testing.T) {
100 collr := test.prepare()
101
102 assert.NotPanics(t, func() { collr.Cleanup(context.Background()) })
103 })
104 }
105 }
106
107 func TestCollector_Charts(t *testing.T) {
108 assert.NotNil(t, New().Charts())
109 }
110
111 func TestCollector_Check(t *testing.T) {
112 tests := map[string]struct {
113 prepareMock func() *mockArcconfExec
114 wantFail bool
115 }{
116 "success case old data": {
117 wantFail: false,
118 prepareMock: prepareMockOkOld,
119 },
120 "success case current data": {
121 wantFail: false,
122 prepareMock: prepareMockOkCurrent,
123 },
124 "success case with enclosure data": {
125 wantFail: false,
126 prepareMock: prepareMockOkWithEnclosure,
127 },
128 "err on exec": {
129 wantFail: true,
130 prepareMock: prepareMockErr,
131 },
132 "unexpected response": {
133 wantFail: true,
134 prepareMock: prepareMockUnexpectedResponse,
135 },
136 "empty response": {
137 wantFail: true,
138 prepareMock: prepareMockEmptyResponse,
139 },
140 }
141
142 for name, test := range tests {
143 t.Run(name, func(t *testing.T) {
144 collr := New()
145 mock := test.prepareMock()
146 collr.exec = mock
147
148 if test.wantFail {
149 assert.Error(t, collr.Check(context.Background()))
150 } else {
151 assert.NoError(t, collr.Check(context.Background()))
152 }
153 })
154 }
155 }
156
157 func TestCollector_Collect(t *testing.T) {
158 tests := map[string]struct {
159 prepareMock func() *mockArcconfExec
160 wantMetrics map[string]int64
161 wantCharts int
162 }{
163 "success case old data": {
164 prepareMock: prepareMockOkOld,
165 wantCharts: len(ldChartsTmpl)*1 + (len(pdChartsTmpl)-1)*4,
166 wantMetrics: map[string]int64{
167 "ld_0_health_state_critical": 0,
168 "ld_0_health_state_ok": 1,
169 "pd_0_health_state_critical": 0,
170 "pd_0_health_state_ok": 1,
171 "pd_0_smart_warnings": 0,
172 "pd_1_health_state_critical": 0,
173 "pd_1_health_state_ok": 1,
174 "pd_1_smart_warnings": 0,
175 "pd_2_health_state_critical": 0,
176 "pd_2_health_state_ok": 1,
177 "pd_2_smart_warnings": 0,
178 "pd_3_health_state_critical": 0,
179 "pd_3_health_state_ok": 1,
180 "pd_3_smart_warnings": 0,
181 },
182 },
183 "success case current data": {
184 prepareMock: prepareMockOkCurrent,
185 wantCharts: len(ldChartsTmpl)*1 + (len(pdChartsTmpl)-1)*6,
186 wantMetrics: map[string]int64{
187 "ld_0_health_state_critical": 0,
188 "ld_0_health_state_ok": 1,
189 "pd_0_health_state_critical": 0,
190 "pd_0_health_state_ok": 1,
191 "pd_0_smart_warnings": 0,
192 "pd_1_health_state_critical": 0,
193 "pd_1_health_state_ok": 1,
194 "pd_1_smart_warnings": 0,
195 "pd_2_health_state_critical": 0,
196 "pd_2_health_state_ok": 1,
197 "pd_2_smart_warnings": 0,
198 "pd_3_health_state_critical": 0,
199 "pd_3_health_state_ok": 1,
200 "pd_3_smart_warnings": 0,
201 "pd_4_health_state_critical": 0,
202 "pd_4_health_state_ok": 1,
203 "pd_4_smart_warnings": 0,
204 "pd_5_health_state_critical": 0,
205 "pd_5_health_state_ok": 1,
206 "pd_5_smart_warnings": 0,
207 },
208 },
209 "success case with enclosure data": {
210 prepareMock: prepareMockOkWithEnclosure,
211 wantCharts: len(ldChartsTmpl)*1 + (len(pdChartsTmpl)-1)*12,
212 wantMetrics: map[string]int64{
213 "ld_0_health_state_critical": 0,
214 "ld_0_health_state_ok": 1,
215 "pd_0_health_state_critical": 0,
216 "pd_0_health_state_ok": 1,
217 "pd_0_smart_warnings": 0,
218 "pd_1_health_state_critical": 0,
219 "pd_1_health_state_ok": 1,
220 "pd_1_smart_warnings": 0,
221 "pd_10_health_state_critical": 0,
222 "pd_10_health_state_ok": 1,
223 "pd_10_smart_warnings": 0,
224 "pd_11_health_state_critical": 0,
225 "pd_11_health_state_ok": 1,
226 "pd_11_smart_warnings": 0,
227 "pd_2_health_state_critical": 0,
228 "pd_2_health_state_ok": 1,
229 "pd_2_smart_warnings": 0,
230 "pd_3_health_state_critical": 0,
231 "pd_3_health_state_ok": 1,
232 "pd_3_smart_warnings": 0,
233 "pd_4_health_state_critical": 0,
234 "pd_4_health_state_ok": 1,
235 "pd_4_smart_warnings": 0,
236 "pd_5_health_state_critical": 0,
237 "pd_5_health_state_ok": 1,
238 "pd_5_smart_warnings": 0,
239 "pd_6_health_state_critical": 0,
240 "pd_6_health_state_ok": 1,
241 "pd_6_smart_warnings": 0,
242 "pd_7_health_state_critical": 0,
243 "pd_7_health_state_ok": 1,
244 "pd_7_smart_warnings": 0,
245 "pd_8_health_state_critical": 0,
246 "pd_8_health_state_ok": 1,
247 "pd_8_smart_warnings": 0,
248 "pd_9_health_state_critical": 0,
249 "pd_9_health_state_ok": 1,
250 "pd_9_smart_warnings": 0,
251 },
252 },
253 "err on exec": {
254 prepareMock: prepareMockErr,
255 },
256 "unexpected response": {
257 prepareMock: prepareMockUnexpectedResponse,
258 },
259 "empty response": {
260 prepareMock: prepareMockUnexpectedResponse,
261 },
262 }
263
264 for name, test := range tests {
265 t.Run(name, func(t *testing.T) {
266 collr := New()
267 mock := test.prepareMock()
268 collr.exec = mock
269
270 mx := collr.Collect(context.Background())
271
272 assert.Equal(t, test.wantMetrics, mx)
273 assert.Len(t, *collr.Charts(), test.wantCharts)
274 })
275 }
276 }
277
278 func prepareMockOkOld() *mockArcconfExec {
279 return &mockArcconfExec{
280 ldData: dataLogicalDevicesOld,
281 pdData: dataPhysicalDevicesOld,
282 }
283 }
284
285 func prepareMockOkCurrent() *mockArcconfExec {
286 return &mockArcconfExec{
287 ldData: dataLogicalDevicesCurrent,
288 pdData: dataPhysicalDevicesCurrent,
289 }
290 }
291
292 func prepareMockOkWithEnclosure() *mockArcconfExec {
293 return &mockArcconfExec{
294 ldData: dataLogicalDevicesCurrent,
295 pdData: dataPhysicalDevicesWithEnclosure,
296 }
297 }
298
299 func prepareMockErr() *mockArcconfExec {
300 return &mockArcconfExec{
301 errOnInfo: true,
302 }
303 }
304
305 func prepareMockUnexpectedResponse() *mockArcconfExec {
306 resp := []byte(`
307 Lorem ipsum dolor sit amet, consectetur adipiscing elit.
308 Nulla malesuada erat id magna mattis, eu viverra tellus rhoncus.
309 Fusce et felis pulvinar, posuere sem non, porttitor eros.
310 `)
311 return &mockArcconfExec{
312 ldData: resp,
313 pdData: resp,
314 }
315 }
316
317 func prepareMockEmptyResponse() *mockArcconfExec {
318 return &mockArcconfExec{}
319 }
320
321 type mockArcconfExec struct {
322 errOnInfo bool
323 ldData []byte
324 pdData []byte
325 }
326
327 func (m *mockArcconfExec) logicalDevicesInfo() ([]byte, error) {
328 if m.errOnInfo {
329 return nil, errors.New("mock.logicalDevicesInfo() error")
330 }
331 return m.ldData, nil
332 }
333
334 func (m *mockArcconfExec) physicalDevicesInfo() ([]byte, error) {
335 if m.errOnInfo {
336 return nil, errors.New("mock.physicalDevicesInfo() error")
337 }
338 return m.pdData, nil
339 }