github.com/netdata/go.d.plugin@v0.58.1/modules/ntpd/ntpd_test.go (about)

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