master
go 374 lines 10.2 KB
Raw
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 package ntpd
4
5 import (
6 "context"
7 "errors"
8 "fmt"
9 "os"
10 "testing"
11
12 "github.com/netdata/netdata/go/plugins/plugin/go.d/pkg/collecttest"
13
14 "github.com/stretchr/testify/assert"
15 "github.com/stretchr/testify/require"
16 )
17
18 var (
19 dataConfigJSON, _ = os.ReadFile("testdata/config.json")
20 dataConfigYAML, _ = os.ReadFile("testdata/config.yaml")
21 )
22
23 func Test_testDataIsValid(t *testing.T) {
24 for name, data := range map[string][]byte{
25 "dataConfigJSON": dataConfigJSON,
26 "dataConfigYAML": dataConfigYAML,
27 } {
28 require.NotNil(t, data, name)
29 }
30 }
31
32 func TestCollector_ConfigurationSerialize(t *testing.T) {
33 collecttest.TestConfigurationSerialize(t, &Collector{}, dataConfigJSON, dataConfigYAML)
34 }
35
36 func TestCollector_Init(t *testing.T) {
37 tests := map[string]struct {
38 config Config
39 wantFail bool
40 }{
41 "default config": {
42 config: New().Config,
43 },
44 "unset 'address'": {
45 wantFail: true,
46 config: Config{
47 Address: "",
48 },
49 },
50 }
51
52 for name, test := range tests {
53 t.Run(name, func(t *testing.T) {
54 collr := New()
55 collr.Config = test.config
56
57 if test.wantFail {
58 assert.Error(t, collr.Init(context.Background()))
59 } else {
60 assert.NoError(t, collr.Init(context.Background()))
61 }
62 })
63 }
64 }
65
66 func TestCollector_Charts(t *testing.T) {
67 assert.Equal(t, len(systemCharts), len(*New().Charts()))
68 }
69
70 func TestCollector_Cleanup(t *testing.T) {
71 tests := map[string]struct {
72 prepare func(*Collector)
73 wantClose bool
74 }{
75 "after New": {
76 wantClose: false,
77 prepare: func(*Collector) {},
78 },
79 "after Init": {
80 wantClose: false,
81 prepare: func(n *Collector) { _ = n.Init(context.Background()) },
82 },
83 "after Check": {
84 wantClose: true,
85 prepare: func(n *Collector) { _ = n.Init(context.Background()); _ = n.Check(context.Background()) },
86 },
87 "after Collect": {
88 wantClose: true,
89 prepare: func(n *Collector) { _ = n.Init(context.Background()); n.Collect(context.Background()) },
90 },
91 }
92
93 for name, test := range tests {
94 t.Run(name, func(t *testing.T) {
95 m := &mockClient{}
96 collr := prepareNTPdWithMock(m, true)
97 test.prepare(collr)
98
99 require.NotPanics(t, func() { collr.Cleanup(context.Background()) })
100
101 if test.wantClose {
102 assert.True(t, m.closeCalled)
103 } else {
104 assert.False(t, m.closeCalled)
105 }
106 })
107 }
108 }
109
110 func TestCollector_Check(t *testing.T) {
111 tests := map[string]struct {
112 prepare func() *Collector
113 wantFail bool
114 }{
115 "system: success, peers: success": {
116 wantFail: false,
117 prepare: func() *Collector { return prepareNTPdWithMock(&mockClient{}, true) },
118 },
119 "system: success, list peers: fails": {
120 wantFail: false,
121 prepare: func() *Collector { return prepareNTPdWithMock(&mockClient{errOnPeerIDs: true}, true) },
122 },
123 "system: success, peers info: fails": {
124 wantFail: false,
125 prepare: func() *Collector { return prepareNTPdWithMock(&mockClient{errOnPeerInfo: true}, true) },
126 },
127 "system: fails": {
128 wantFail: true,
129 prepare: func() *Collector { return prepareNTPdWithMock(&mockClient{errOnSystemInfo: true}, true) },
130 },
131 "fail on creating client": {
132 wantFail: true,
133 prepare: func() *Collector { return prepareNTPdWithMock(nil, true) },
134 },
135 }
136
137 for name, test := range tests {
138 t.Run(name, func(t *testing.T) {
139 collr := test.prepare()
140
141 require.NoError(t, collr.Init(context.Background()))
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
153 func TestCollector_Collect(t *testing.T) {
154 tests := map[string]struct {
155 prepare func() *Collector
156 expected map[string]int64
157 expectedCharts int
158 }{
159 "system: success, peers: success": {
160 prepare: func() *Collector { return prepareNTPdWithMock(&mockClient{}, true) },
161 expected: map[string]int64{
162 "clk_jitter": 626000,
163 "clk_wander": 81000,
164 "mintc": 3000000,
165 "offset": -149638,
166 "peer_203.0.113.1_delay": 10464000,
167 "peer_203.0.113.1_dispersion": 5376000,
168 "peer_203.0.113.1_hmode": 3000000,
169 "peer_203.0.113.1_hpoll": 7000000,
170 "peer_203.0.113.1_jitter": 5204000,
171 "peer_203.0.113.1_offset": 312000,
172 "peer_203.0.113.1_pmode": 4000000,
173 "peer_203.0.113.1_ppoll": 7000000,
174 "peer_203.0.113.1_precision": -21000000,
175 "peer_203.0.113.1_rootdelay": 198000,
176 "peer_203.0.113.1_rootdisp": 14465000,
177 "peer_203.0.113.1_stratum": 2000000,
178 "peer_203.0.113.1_xleave": 95000,
179 "peer_203.0.113.2_delay": 10464000,
180 "peer_203.0.113.2_dispersion": 5376000,
181 "peer_203.0.113.2_hmode": 3000000,
182 "peer_203.0.113.2_hpoll": 7000000,
183 "peer_203.0.113.2_jitter": 5204000,
184 "peer_203.0.113.2_offset": 312000,
185 "peer_203.0.113.2_pmode": 4000000,
186 "peer_203.0.113.2_ppoll": 7000000,
187 "peer_203.0.113.2_precision": -21000000,
188 "peer_203.0.113.2_rootdelay": 198000,
189 "peer_203.0.113.2_rootdisp": 14465000,
190 "peer_203.0.113.2_stratum": 2000000,
191 "peer_203.0.113.2_xleave": 95000,
192 "peer_203.0.113.3_delay": 10464000,
193 "peer_203.0.113.3_dispersion": 5376000,
194 "peer_203.0.113.3_hmode": 3000000,
195 "peer_203.0.113.3_hpoll": 7000000,
196 "peer_203.0.113.3_jitter": 5204000,
197 "peer_203.0.113.3_offset": 312000,
198 "peer_203.0.113.3_pmode": 4000000,
199 "peer_203.0.113.3_ppoll": 7000000,
200 "peer_203.0.113.3_precision": -21000000,
201 "peer_203.0.113.3_rootdelay": 198000,
202 "peer_203.0.113.3_rootdisp": 14465000,
203 "peer_203.0.113.3_stratum": 2000000,
204 "peer_203.0.113.3_xleave": 95000,
205 "precision": -24000000,
206 "rootdelay": 10385000,
207 "rootdisp": 23404000,
208 "stratum": 2000000,
209 "sys_jitter": 1648010,
210 "tc": 7000000,
211 },
212 expectedCharts: len(systemCharts) + len(peerChartsTmpl)*3,
213 },
214 "system: success, list peers: fails": {
215 prepare: func() *Collector { return prepareNTPdWithMock(&mockClient{errOnPeerIDs: true}, true) },
216 expected: map[string]int64{
217 "clk_jitter": 626000,
218 "clk_wander": 81000,
219 "mintc": 3000000,
220 "offset": -149638,
221 "precision": -24000000,
222 "rootdelay": 10385000,
223 "rootdisp": 23404000,
224 "stratum": 2000000,
225 "sys_jitter": 1648010,
226 "tc": 7000000,
227 },
228 expectedCharts: len(systemCharts),
229 },
230 "system: success, peers info: fails": {
231 prepare: func() *Collector { return prepareNTPdWithMock(&mockClient{errOnPeerInfo: true}, true) },
232 expected: map[string]int64{
233 "clk_jitter": 626000,
234 "clk_wander": 81000,
235 "mintc": 3000000,
236 "offset": -149638,
237 "precision": -24000000,
238 "rootdelay": 10385000,
239 "rootdisp": 23404000,
240 "stratum": 2000000,
241 "sys_jitter": 1648010,
242 "tc": 7000000,
243 },
244 expectedCharts: len(systemCharts),
245 },
246 "system: fails": {
247 prepare: func() *Collector { return prepareNTPdWithMock(&mockClient{errOnSystemInfo: true}, true) },
248 expected: nil,
249 expectedCharts: len(systemCharts),
250 },
251 "fail on creating client": {
252 prepare: func() *Collector { return prepareNTPdWithMock(nil, true) },
253 expected: nil,
254 expectedCharts: len(systemCharts),
255 },
256 }
257
258 for name, test := range tests {
259 t.Run(name, func(t *testing.T) {
260 collr := test.prepare()
261
262 require.NoError(t, collr.Init(context.Background()))
263
264 _ = collr.Check(context.Background())
265
266 mx := collr.Collect(context.Background())
267
268 assert.Equal(t, test.expected, mx)
269 assert.Equal(t, test.expectedCharts, len(*collr.Charts()))
270 })
271 }
272 }
273
274 func prepareNTPdWithMock(m *mockClient, collectPeers bool) *Collector {
275 collr := New()
276 collr.CollectPeers = collectPeers
277 if m == nil {
278 collr.newClient = func(_ Config) (ntpConn, error) { return nil, errors.New("mock.newClient error") }
279 } else {
280 collr.newClient = func(_ Config) (ntpConn, error) { return m, nil }
281 }
282 return collr
283 }
284
285 type mockClient struct {
286 errOnSystemInfo bool
287 errOnPeerInfo bool
288 errOnPeerIDs bool
289 closeCalled bool
290 }
291
292 func (m *mockClient) systemInfo() (map[string]string, error) {
293 if m.errOnSystemInfo {
294 return nil, errors.New("mockClient.info() error")
295 }
296
297 info := map[string]string{
298 "rootdelay": "10.385",
299 "tc": "7",
300 "mintc": "3",
301 "processor": "x86_64",
302 "refid": "194.177.210.54",
303 "reftime": "0xe7504a10.74414244",
304 "clock": "0xe7504e80.8c46aa3f",
305 "peer": "14835",
306 "sys_jitter": "1.648010",
307 "leapsec": "201701010000",
308 "expire": "202306280000",
309 "leap": "0",
310 "stratum": "2",
311 "precision": "-24",
312 "offset": "-0.149638",
313 "frequency": "- 7.734",
314 "clk_wander": "0.081",
315 "tai": "37",
316 "version": "ntpd 4.2.8p15@1.3728-o Wed Sep 23 11:46:38 UTC 2020 (1)",
317 "rootdisp": "23.404",
318 "clk_jitter": "0.626",
319 "system": "Linux/5.10.0-19-amd64",
320 }
321
322 return info, nil
323 }
324
325 func (m *mockClient) peerInfo(id uint16) (map[string]string, error) {
326 if m.errOnPeerInfo {
327 return nil, errors.New("mockClient.peerInfo() error")
328 }
329
330 info := map[string]string{
331 "delay": "10.464",
332 "dispersion": "5.376",
333 "dstadr": "10.10.10.20",
334 "dstport": "123",
335 "filtdelay": "11.34 10.53 10.49 10.46 10.92 10.56 10.69 37.99",
336 "filtdisp": "0.00 2.01 4.01 5.93 7.89 9.84 11.81 13.73",
337 "filtoffset": "0.66 0.32 0.18 0.31 0.33 0.10 0.34 14.07",
338 "flash": "0x0",
339 "headway": "0",
340 "hmode": "3",
341 "hpoll": "7",
342 "jitter": "5.204",
343 "keyid": "0",
344 "leap": "0",
345 "offset": "0.312",
346 "pmode": "4",
347 "ppoll": "7",
348 "precision": "-21",
349 "reach": "0xff",
350 "rec": "0xe7504df8.74802284",
351 "refid": "193.93.164.193",
352 "reftime": "0xe7504b8b.0c98a518",
353 "rootdelay": "0.198",
354 "rootdisp": "14.465",
355 "srcadr": fmt.Sprintf("203.0.113.%d", id),
356 "srcport": "123",
357 "stratum": "2",
358 "unreach": "0",
359 "xleave": "0.095",
360 }
361
362 return info, nil
363 }
364
365 func (m *mockClient) peerIDs() ([]uint16, error) {
366 if m.errOnPeerIDs {
367 return nil, errors.New("mockClient.peerIDs() error")
368 }
369 return []uint16{1, 2, 3}, nil
370 }
371
372 func (m *mockClient) close() {
373 m.closeCalled = true
374 }