master
go 280 lines 7.56 KB
Raw
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 package ethtool
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 dataModuleDdm, _ = os.ReadFile("testdata/ddm.txt")
22 dataModuleDdmNoFiber, _ = os.ReadFile("testdata/ddm-no-fiber.txt")
23 dataModuleNoDdm, _ = os.ReadFile("testdata/no-ddm.txt")
24 )
25
26 func Test_testDataIsValid(t *testing.T) {
27 for name, data := range map[string][]byte{
28 "dataConfigJSON": dataConfigJSON,
29 "dataConfigYAML": dataConfigYAML,
30
31 "dataModuleDdm": dataModuleDdm,
32 "dataModuleDdmNoFiber": dataModuleDdmNoFiber,
33 "dataModuleNoDdm": dataModuleNoDdm,
34 } {
35 require.NotNil(t, data, name)
36
37 }
38 }
39
40 func TestCollector_Configuration(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 if failed to locate ndsudo": {
50 wantFail: true,
51 config: New().Config,
52 },
53 }
54
55 for name, test := range tests {
56 t.Run(name, func(t *testing.T) {
57 collr := New()
58 collr.Config = test.config
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 = prepareMockEepromDdm()
82 _ = collr.Check(context.Background())
83 return collr
84 },
85 },
86 "after collect": {
87 prepare: func() *Collector {
88 collr := New()
89 collr.exec = prepareMockEepromDdm()
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() *mockEthtoolExec
112 wantFail bool
113 }{
114 "module with ddm": {
115 wantFail: false,
116 prepareMock: prepareMockEepromDdm,
117 },
118 "module with ddm no fiber": {
119 wantFail: false,
120 prepareMock: prepareMockEepromDdmNoFiber,
121 },
122 "module without ddm": {
123 wantFail: true,
124 prepareMock: prepareMockEepromNoDdm,
125 },
126 "moduleEeprom() error": {
127 wantFail: true,
128 prepareMock: prepareMockEepromError,
129 },
130 "moduleEeprom() unexpected response": {
131 wantFail: true,
132 prepareMock: prepareMockEepromUnexpectedResponse,
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 collr.OpticInterfaces = "eth1 eth2"
142
143 if test.wantFail {
144 assert.Error(t, collr.Check(context.Background()))
145 } else {
146 assert.NoError(t, collr.Check(context.Background()))
147 }
148 })
149 }
150 }
151
152 func TestCollector_Collect(t *testing.T) {
153 tests := map[string]struct {
154 prepareMock func() *mockEthtoolExec
155 wantMetrics map[string]int64
156 wantCharts int
157 }{
158 "module with ddm": {
159 prepareMock: prepareMockEepromDdm,
160 wantCharts: len(ifaceModuleEepromCharts) * 2,
161 wantMetrics: map[string]int64{
162 "iface_eth1_laser_bias_current_ma": 13088,
163 "iface_eth1_laser_output_power_dbm": 5580,
164 "iface_eth1_laser_output_power_mw": 3611,
165 "iface_eth1_module_temperature_c": 38000,
166 "iface_eth1_module_temperature_f": 100400,
167 "iface_eth1_module_voltage_v": 3484,
168 "iface_eth1_receiver_signal_average_optical_power_dbm": -23570,
169 "iface_eth1_receiver_signal_average_optical_power_mw": 4,
170 "iface_eth2_laser_bias_current_ma": 13088,
171 "iface_eth2_laser_output_power_dbm": 5580,
172 "iface_eth2_laser_output_power_mw": 3611,
173 "iface_eth2_module_temperature_c": 38000,
174 "iface_eth2_module_temperature_f": 100400,
175 "iface_eth2_module_voltage_v": 3484,
176 "iface_eth2_receiver_signal_average_optical_power_dbm": -23570,
177 "iface_eth2_receiver_signal_average_optical_power_mw": 4,
178 },
179 },
180 "module with ddm no fiber": {
181 prepareMock: prepareMockEepromDdmNoFiber,
182 wantCharts: len(ifaceModuleEepromCharts) * 2,
183 wantMetrics: map[string]int64{
184 "iface_eth1_laser_bias_current_ma": 12768,
185 "iface_eth1_laser_output_power_dbm": 4840,
186 "iface_eth1_laser_output_power_mw": 3048,
187 "iface_eth1_module_temperature_c": 36750,
188 "iface_eth1_module_temperature_f": 98150,
189 "iface_eth1_module_voltage_v": 3486,
190 "iface_eth1_receiver_signal_average_optical_power_dbm": -40000,
191 "iface_eth1_receiver_signal_average_optical_power_mw": 0,
192 "iface_eth2_laser_bias_current_ma": 12768,
193 "iface_eth2_laser_output_power_dbm": 4840,
194 "iface_eth2_laser_output_power_mw": 3048,
195 "iface_eth2_module_temperature_c": 36750,
196 "iface_eth2_module_temperature_f": 98150,
197 "iface_eth2_module_voltage_v": 3486,
198 "iface_eth2_receiver_signal_average_optical_power_dbm": -40000,
199 "iface_eth2_receiver_signal_average_optical_power_mw": 0,
200 },
201 },
202 "module without ddm": {
203 prepareMock: prepareMockEepromNoDdm,
204 wantMetrics: nil,
205 },
206 "moduleEeprom() error": {
207 prepareMock: prepareMockEepromError,
208 wantMetrics: nil,
209 },
210 "moduleEeprom() unexpected response": {
211 prepareMock: prepareMockEepromUnexpectedResponse,
212 wantMetrics: nil,
213 },
214 }
215
216 for name, test := range tests {
217 t.Run(name, func(t *testing.T) {
218 collr := New()
219 mock := test.prepareMock()
220 collr.exec = mock
221 collr.OpticInterfaces = "eth1 eth2"
222
223 mx := collr.Collect(context.Background())
224
225 require.Equal(t, test.wantMetrics, mx)
226
227 assert.Equal(t, test.wantCharts, test.wantCharts, "want charts")
228
229 if len(test.wantMetrics) > 0 {
230 collecttest.TestMetricsHasAllChartsDims(t, collr.Charts(), mx)
231 }
232 })
233 }
234 }
235
236 func prepareMockEepromDdm() *mockEthtoolExec {
237 return &mockEthtoolExec{
238 moduleEepromData: dataModuleDdm,
239 }
240 }
241
242 func prepareMockEepromDdmNoFiber() *mockEthtoolExec {
243 return &mockEthtoolExec{
244 moduleEepromData: dataModuleDdmNoFiber,
245 }
246 }
247
248 func prepareMockEepromNoDdm() *mockEthtoolExec {
249 return &mockEthtoolExec{
250 moduleEepromData: dataModuleNoDdm,
251 }
252 }
253
254 func prepareMockEepromError() *mockEthtoolExec {
255 return &mockEthtoolExec{
256 errOnModuleEeprom: true,
257 }
258 }
259
260 func prepareMockEepromUnexpectedResponse() *mockEthtoolExec {
261 return &mockEthtoolExec{
262 moduleEepromData: []byte(`
263 Lorem ipsum dolor sit amet, consectetur adipiscing elit.
264 Nulla malesuada erat id magna mattis, eu viverra tellus rhoncus.
265 Fusce et felis pulvinar, posuere sem non, porttitor eros.
266 `),
267 }
268 }
269
270 type mockEthtoolExec struct {
271 errOnModuleEeprom bool
272 moduleEepromData []byte
273 }
274
275 func (m *mockEthtoolExec) moduleEeprom(_ string) ([]byte, error) {
276 if m.errOnModuleEeprom {
277 return nil, errors.New("mock.moduleEeprom() error")
278 }
279 return m.moduleEepromData, nil
280 }