master
go 322 lines 9.42 KB
Raw
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 package megacli
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 dataBBUInfoOld, _ = os.ReadFile("testdata/mega-bbu-info-old.txt")
22 dataBBUInfoRecent, _ = os.ReadFile("testdata/mega-bbu-info-recent.txt")
23 dataPhysDrivesInfo, _ = os.ReadFile("testdata/mega-phys-drives-info.txt")
24 dataPhysDrivesInfoNoDrives, _ = os.ReadFile("testdata/mega-phys-drives-info-no-drives.txt")
25 )
26
27 func Test_testDataIsValid(t *testing.T) {
28 for name, data := range map[string][]byte{
29 "dataConfigJSON": dataConfigJSON,
30 "dataConfigYAML": dataConfigYAML,
31
32 "dataBBUInfoOld": dataBBUInfoOld,
33 "dataBBUInfoRecent": dataBBUInfoRecent,
34 "dataPhysDrivesInfo": dataPhysDrivesInfo,
35 "dataPhysDrivesInfoNoDrives": dataPhysDrivesInfoNoDrives,
36 } {
37 require.NotNil(t, data, name)
38 }
39 }
40
41 func TestCollector_ConfigurationSerialize(t *testing.T) {
42 collecttest.TestConfigurationSerialize(t, &Collector{}, dataConfigJSON, dataConfigYAML)
43 }
44
45 func TestCollector_Init(t *testing.T) {
46 tests := map[string]struct {
47 config Config
48 wantFail bool
49 }{
50 "success with default config": {
51 wantFail: false,
52 config: New().Config,
53 },
54 }
55
56 for name, test := range tests {
57 t.Run(name, func(t *testing.T) {
58 collr := New()
59
60 if test.wantFail {
61 assert.Error(t, collr.Init(context.Background()))
62 } else {
63 assert.NoError(t, collr.Init(context.Background()))
64 }
65 })
66 }
67 }
68
69 func TestCollector_Cleanup(t *testing.T) {
70 tests := map[string]struct {
71 prepare func() *Collector
72 }{
73 "not initialized exec": {
74 prepare: func() *Collector {
75 return New()
76 },
77 },
78 "after check": {
79 prepare: func() *Collector {
80 collr := New()
81 collr.exec = prepareMockOK()
82 _ = collr.Check(context.Background())
83 return collr
84 },
85 },
86 "after collect": {
87 prepare: func() *Collector {
88 collr := New()
89 collr.exec = prepareMockOK()
90 _ = collr.Collect(context.Background())
91 return collr
92 },
93 },
94 }
95
96 for name, test := range tests {
97 t.Run(name, func(t *testing.T) {
98 collr := test.prepare()
99
100 assert.NotPanics(t, func() { collr.Cleanup(context.Background()) })
101 })
102 }
103 }
104
105 func TestCollector_Charts(t *testing.T) {
106 assert.NotNil(t, New().Charts())
107 }
108
109 func TestCollector_Check(t *testing.T) {
110 tests := map[string]struct {
111 prepareMock func() *mockMegaCliExec
112 wantFail bool
113 }{
114 "success case": {
115 wantFail: false,
116 prepareMock: prepareMockOK,
117 },
118 "success case old bbu": {
119 wantFail: false,
120 prepareMock: prepareMockOldBbuOK,
121 },
122 "err on exec": {
123 wantFail: true,
124 prepareMock: prepareMockErr,
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.exec = 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() *mockMegaCliExec
154 wantMetrics map[string]int64
155 wantCharts int
156 }{
157 "success case": {
158 prepareMock: prepareMockOK,
159 wantCharts: len(adapterChartsTmpl)*1 + len(physDriveChartsTmpl)*8 + len(bbuChartsTmpl)*1,
160 wantMetrics: map[string]int64{
161 "adapter_0_health_state_degraded": 0,
162 "adapter_0_health_state_failed": 0,
163 "adapter_0_health_state_optimal": 1,
164 "adapter_0_health_state_partially_degraded": 0,
165 "bbu_adapter_0_absolute_state_of_charge": 63,
166 "bbu_adapter_0_capacity_degradation_perc": 10,
167 "bbu_adapter_0_cycle_count": 4,
168 "bbu_adapter_0_relative_state_of_charge": 71,
169 "bbu_adapter_0_temperature": 33,
170 "phys_drive_5002538c00019b96_media_error_count": 0,
171 "phys_drive_5002538c00019b96_predictive_failure_count": 0,
172 "phys_drive_5002538c4002da83_media_error_count": 0,
173 "phys_drive_5002538c4002da83_predictive_failure_count": 0,
174 "phys_drive_5002538c4002dade_media_error_count": 0,
175 "phys_drive_5002538c4002dade_predictive_failure_count": 0,
176 "phys_drive_5002538c4002e6e9_media_error_count": 0,
177 "phys_drive_5002538c4002e6e9_predictive_failure_count": 0,
178 "phys_drive_5002538c4002e707_media_error_count": 0,
179 "phys_drive_5002538c4002e707_predictive_failure_count": 0,
180 "phys_drive_5002538c4002e70f_media_error_count": 0,
181 "phys_drive_5002538c4002e70f_predictive_failure_count": 0,
182 "phys_drive_5002538c4002e712_media_error_count": 0,
183 "phys_drive_5002538c4002e712_predictive_failure_count": 0,
184 "phys_drive_5002538c4002e713_media_error_count": 0,
185 "phys_drive_5002538c4002e713_predictive_failure_count": 0,
186 },
187 },
188 "success case old bbu": {
189 prepareMock: prepareMockOldBbuOK,
190 wantCharts: len(adapterChartsTmpl)*1 + len(physDriveChartsTmpl)*8 + len(bbuChartsTmpl)*1,
191 wantMetrics: map[string]int64{
192 "adapter_0_health_state_degraded": 0,
193 "adapter_0_health_state_failed": 0,
194 "adapter_0_health_state_optimal": 1,
195 "adapter_0_health_state_partially_degraded": 0,
196 "bbu_adapter_0_absolute_state_of_charge": 83,
197 "bbu_adapter_0_capacity_degradation_perc": 17,
198 "bbu_adapter_0_cycle_count": 61,
199 "bbu_adapter_0_relative_state_of_charge": 100,
200 "bbu_adapter_0_temperature": 31,
201 "phys_drive_5002538c00019b96_media_error_count": 0,
202 "phys_drive_5002538c00019b96_predictive_failure_count": 0,
203 "phys_drive_5002538c4002da83_media_error_count": 0,
204 "phys_drive_5002538c4002da83_predictive_failure_count": 0,
205 "phys_drive_5002538c4002dade_media_error_count": 0,
206 "phys_drive_5002538c4002dade_predictive_failure_count": 0,
207 "phys_drive_5002538c4002e6e9_media_error_count": 0,
208 "phys_drive_5002538c4002e6e9_predictive_failure_count": 0,
209 "phys_drive_5002538c4002e707_media_error_count": 0,
210 "phys_drive_5002538c4002e707_predictive_failure_count": 0,
211 "phys_drive_5002538c4002e70f_media_error_count": 0,
212 "phys_drive_5002538c4002e70f_predictive_failure_count": 0,
213 "phys_drive_5002538c4002e712_media_error_count": 0,
214 "phys_drive_5002538c4002e712_predictive_failure_count": 0,
215 "phys_drive_5002538c4002e713_media_error_count": 0,
216 "phys_drive_5002538c4002e713_predictive_failure_count": 0,
217 },
218 },
219 "adapter with disconnected drives": {
220 prepareMock: prepareMockNoDrives,
221 wantCharts: len(bbuChartsTmpl) * 1,
222 wantMetrics: map[string]int64{
223 "bbu_adapter_0_absolute_state_of_charge": 63,
224 "bbu_adapter_0_capacity_degradation_perc": 10,
225 "bbu_adapter_0_cycle_count": 4,
226 "bbu_adapter_0_relative_state_of_charge": 71,
227 "bbu_adapter_0_temperature": 33,
228 },
229 },
230 "err on exec": {
231 prepareMock: prepareMockErr,
232 wantMetrics: nil,
233 },
234 "unexpected response": {
235 prepareMock: prepareMockUnexpectedResponse,
236 wantMetrics: nil,
237 },
238 "empty response": {
239 prepareMock: prepareMockEmptyResponse,
240 wantMetrics: nil,
241 },
242 }
243
244 for name, test := range tests {
245 t.Run(name, func(t *testing.T) {
246 collr := New()
247 mock := test.prepareMock()
248 collr.exec = mock
249
250 mx := collr.Collect(context.Background())
251
252 assert.Equal(t, test.wantMetrics, mx)
253 assert.Len(t, *collr.Charts(), test.wantCharts)
254 if len(test.wantMetrics) > 0 {
255 collecttest.TestMetricsHasAllChartsDims(t, collr.Charts(), mx)
256 }
257 })
258 }
259 }
260
261 func prepareMockOK() *mockMegaCliExec {
262 return &mockMegaCliExec{
263 physDrivesInfoData: dataPhysDrivesInfo,
264 bbuInfoData: dataBBUInfoRecent,
265 }
266 }
267
268 func prepareMockNoDrives() *mockMegaCliExec {
269 return &mockMegaCliExec{
270 physDrivesInfoData: dataPhysDrivesInfoNoDrives,
271 bbuInfoData: dataBBUInfoRecent,
272 }
273 }
274
275 func prepareMockOldBbuOK() *mockMegaCliExec {
276 return &mockMegaCliExec{
277 physDrivesInfoData: dataPhysDrivesInfo,
278 bbuInfoData: dataBBUInfoOld,
279 }
280 }
281
282 func prepareMockErr() *mockMegaCliExec {
283 return &mockMegaCliExec{
284 errOnInfo: true,
285 }
286 }
287
288 func prepareMockUnexpectedResponse() *mockMegaCliExec {
289 resp := []byte(`
290 Lorem ipsum dolor sit amet, consectetur adipiscing elit.
291 Nulla malesuada erat id magna mattis, eu viverra tellus rhoncus.
292 Fusce et felis pulvinar, posuere sem non, porttitor eros.
293 `)
294 return &mockMegaCliExec{
295 physDrivesInfoData: resp,
296 bbuInfoData: resp,
297 }
298 }
299
300 func prepareMockEmptyResponse() *mockMegaCliExec {
301 return &mockMegaCliExec{}
302 }
303
304 type mockMegaCliExec struct {
305 errOnInfo bool
306 physDrivesInfoData []byte
307 bbuInfoData []byte
308 }
309
310 func (m *mockMegaCliExec) physDrivesInfo() ([]byte, error) {
311 if m.errOnInfo {
312 return nil, errors.New("mock.physDrivesInfo() error")
313 }
314 return m.physDrivesInfoData, nil
315 }
316
317 func (m *mockMegaCliExec) bbuInfo() ([]byte, error) {
318 if m.errOnInfo {
319 return nil, errors.New("mock.bbuInfo() error")
320 }
321 return m.bbuInfoData, nil
322 }