package ethtool import ( "net" "testing" "github.com/influxdata/telegraf/testutil" "github.com/pkg/errors" "github.com/stretchr/testify/assert" ) var command *Ethtool var interfaceMap map[string]*InterfaceMock type InterfaceMock struct { Name string DriverName string Stat map[string]uint64 LoopBack bool } type CommandEthtoolMock struct { InterfaceMap map[string]*InterfaceMock } func (c *CommandEthtoolMock) Init() error { // Not required for test mock return nil } func (c *CommandEthtoolMock) DriverName(intf string) (driverName string, err error) { i := c.InterfaceMap[intf] if i != nil { driverName = i.DriverName return } return driverName, errors.New("interface not found") } func (c *CommandEthtoolMock) Interfaces() ([]net.Interface, error) { interfaceNames := make([]net.Interface, 0) for k, v := range c.InterfaceMap { // Whether to set the flag to loopback flag := net.FlagUp if v.LoopBack { flag = net.FlagLoopback } // Create a dummy interface iface := net.Interface{ Index: 0, MTU: 1500, Name: k, HardwareAddr: nil, Flags: flag, } interfaceNames = append(interfaceNames, iface) } return interfaceNames, nil } func (c *CommandEthtoolMock) Stats(intf string) (stat map[string]uint64, err error) { i := c.InterfaceMap[intf] if i != nil { stat = i.Stat return } return stat, errors.New("interface not found") } func setup() { interfaceMap = make(map[string]*InterfaceMock) eth1Stat := map[string]uint64{ "port_rx_1024_to_15xx": 25167245, "port_rx_128_to_255": 1573526387, "port_rx_15xx_to_jumbo": 137819058, "port_rx_256_to_511": 772038107, "port_rx_512_to_1023": 78294457, "port_rx_64": 8798065, "port_rx_65_to_127": 450348015, "port_rx_bad": 0, "port_rx_bad_bytes": 0, "port_rx_bad_gtjumbo": 0, "port_rx_broadcast": 6428250, "port_rx_bytes": 893460472634, "port_rx_control": 0, "port_rx_dp_di_dropped_packets": 2772680304, "port_rx_dp_hlb_fetch": 0, "port_rx_dp_hlb_wait": 0, "port_rx_dp_q_disabled_packets": 0, "port_rx_dp_streaming_packets": 0, "port_rx_good": 3045991334, "port_rx_good_bytes": 893460472927, "port_rx_gtjumbo": 0, "port_rx_lt64": 0, "port_rx_multicast": 1639566045, "port_rx_nodesc_drops": 0, "port_rx_overflow": 0, "port_rx_packets": 3045991334, "port_rx_pause": 0, "port_rx_pm_discard_bb_overflow": 0, "port_rx_pm_discard_mapping": 0, "port_rx_pm_discard_qbb": 0, "port_rx_pm_discard_vfifo_full": 0, "port_rx_pm_trunc_bb_overflow": 0, "port_rx_pm_trunc_qbb": 0, "port_rx_pm_trunc_vfifo_full": 0, "port_rx_unicast": 1399997040, "port_tx_1024_to_15xx": 236, "port_tx_128_to_255": 275090219, "port_tx_15xx_to_jumbo": 926, "port_tx_256_to_511": 48567221, "port_tx_512_to_1023": 5142016, "port_tx_64": 113903973, "port_tx_65_to_127": 161935699, "port_tx_broadcast": 8, "port_tx_bytes": 94357131016, "port_tx_control": 0, "port_tx_lt64": 0, "port_tx_multicast": 325891647, "port_tx_packets": 604640290, "port_tx_pause": 0, "port_tx_unicast": 278748635, "ptp_bad_syncs": 1, "ptp_fast_syncs": 1, "ptp_filter_matches": 0, "ptp_good_syncs": 136151, "ptp_invalid_sync_windows": 0, "ptp_no_time_syncs": 1, "ptp_non_filter_matches": 0, "ptp_oversize_sync_windows": 53, "ptp_rx_no_timestamp": 0, "ptp_rx_timestamp_packets": 0, "ptp_sync_timeouts": 1, "ptp_timestamp_packets": 0, "ptp_tx_timestamp_packets": 0, "ptp_undersize_sync_windows": 3, "rx-0.rx_packets": 55659234, "rx-1.rx_packets": 87880538, "rx-2.rx_packets": 26746234, "rx-3.rx_packets": 103026471, "rx-4.rx_packets": 0, "rx_eth_crc_err": 0, "rx_frm_trunc": 0, "rx_inner_ip_hdr_chksum_err": 0, "rx_inner_tcp_udp_chksum_err": 0, "rx_ip_hdr_chksum_err": 0, "rx_mcast_mismatch": 0, "rx_merge_events": 0, "rx_merge_packets": 0, "rx_nodesc_trunc": 0, "rx_noskb_drops": 0, "rx_outer_ip_hdr_chksum_err": 0, "rx_outer_tcp_udp_chksum_err": 0, "rx_reset": 0, "rx_tcp_udp_chksum_err": 0, "rx_tobe_disc": 0, "tx-0.tx_packets": 85843565, "tx-1.tx_packets": 108642725, "tx-2.tx_packets": 202596078, "tx-3.tx_packets": 207561010, "tx-4.tx_packets": 0, "tx_cb_packets": 4, "tx_merge_events": 11025, "tx_pio_packets": 531928114, "tx_pushes": 604643378, "tx_tso_bursts": 0, "tx_tso_fallbacks": 0, "tx_tso_long_headers": 0, } eth1 := &InterfaceMock{"eth1", "driver1", eth1Stat, false} interfaceMap[eth1.Name] = eth1 eth2Stat := map[string]uint64{ "port_rx_1024_to_15xx": 11529312, "port_rx_128_to_255": 1868952037, "port_rx_15xx_to_jumbo": 130339387, "port_rx_256_to_511": 843846270, "port_rx_512_to_1023": 173194372, "port_rx_64": 9190374, "port_rx_65_to_127": 507806115, "port_rx_bad": 0, "port_rx_bad_bytes": 0, "port_rx_bad_gtjumbo": 0, "port_rx_broadcast": 6648019, "port_rx_bytes": 1007358162202, "port_rx_control": 0, "port_rx_dp_di_dropped_packets": 3164124639, "port_rx_dp_hlb_fetch": 0, "port_rx_dp_hlb_wait": 0, "port_rx_dp_q_disabled_packets": 0, "port_rx_dp_streaming_packets": 0, "port_rx_good": 3544857867, "port_rx_good_bytes": 1007358162202, "port_rx_gtjumbo": 0, "port_rx_lt64": 0, "port_rx_multicast": 2231999743, "port_rx_nodesc_drops": 0, "port_rx_overflow": 0, "port_rx_packets": 3544857867, "port_rx_pause": 0, "port_rx_pm_discard_bb_overflow": 0, "port_rx_pm_discard_mapping": 0, "port_rx_pm_discard_qbb": 0, "port_rx_pm_discard_vfifo_full": 0, "port_rx_pm_trunc_bb_overflow": 0, "port_rx_pm_trunc_qbb": 0, "port_rx_pm_trunc_vfifo_full": 0, "port_rx_unicast": 1306210105, "port_tx_1024_to_15xx": 379, "port_tx_128_to_255": 202767251, "port_tx_15xx_to_jumbo": 558, "port_tx_256_to_511": 31454719, "port_tx_512_to_1023": 6865731, "port_tx_64": 17268276, "port_tx_65_to_127": 272816313, "port_tx_broadcast": 6, "port_tx_bytes": 78071946593, "port_tx_control": 0, "port_tx_lt64": 0, "port_tx_multicast": 239510586, "port_tx_packets": 531173227, "port_tx_pause": 0, "port_tx_unicast": 291662635, "ptp_bad_syncs": 0, "ptp_fast_syncs": 0, "ptp_filter_matches": 0, "ptp_good_syncs": 0, "ptp_invalid_sync_windows": 0, "ptp_no_time_syncs": 0, "ptp_non_filter_matches": 0, "ptp_oversize_sync_windows": 0, "ptp_rx_no_timestamp": 0, "ptp_rx_timestamp_packets": 0, "ptp_sync_timeouts": 0, "ptp_timestamp_packets": 0, "ptp_tx_timestamp_packets": 0, "ptp_undersize_sync_windows": 0, "rx-0.rx_packets": 84587075, "rx-1.rx_packets": 74029305, "rx-2.rx_packets": 134586471, "rx-3.rx_packets": 87531322, "rx-4.rx_packets": 0, "rx_eth_crc_err": 0, "rx_frm_trunc": 0, "rx_inner_ip_hdr_chksum_err": 0, "rx_inner_tcp_udp_chksum_err": 0, "rx_ip_hdr_chksum_err": 0, "rx_mcast_mismatch": 0, "rx_merge_events": 0, "rx_merge_packets": 0, "rx_nodesc_trunc": 0, "rx_noskb_drops": 0, "rx_outer_ip_hdr_chksum_err": 0, "rx_outer_tcp_udp_chksum_err": 0, "rx_reset": 0, "rx_tcp_udp_chksum_err": 0, "rx_tobe_disc": 0, "tx-0.tx_packets": 232521451, "tx-1.tx_packets": 97876137, "tx-2.tx_packets": 106822111, "tx-3.tx_packets": 93955050, "tx-4.tx_packets": 0, "tx_cb_packets": 1, "tx_merge_events": 8402, "tx_pio_packets": 481040054, "tx_pushes": 531174491, "tx_tso_bursts": 128, "tx_tso_fallbacks": 0, "tx_tso_long_headers": 0, } eth2 := &InterfaceMock{"eth2", "driver1", eth2Stat, false} interfaceMap[eth2.Name] = eth2 // dummy loopback including dummy stat to ensure that the ignore feature is working lo0Stat := map[string]uint64{ "dummy": 0, } lo0 := &InterfaceMock{"lo0", "", lo0Stat, true} interfaceMap[lo0.Name] = lo0 c := &CommandEthtoolMock{interfaceMap} command = &Ethtool{ InterfaceInclude: []string{}, InterfaceExclude: []string{}, command: c, } } func toStringMapInterface(in map[string]uint64) map[string]interface{} { var m = map[string]interface{}{} for k, v := range in { m[k] = v } return m } func TestGather(t *testing.T) { setup() var acc testutil.Accumulator err := command.Gather(&acc) assert.NoError(t, err) assert.Len(t, acc.Metrics, 2) expectedFieldsEth1 := toStringMapInterface(interfaceMap["eth1"].Stat) expectedTagsEth1 := map[string]string{ "interface": "eth1", "driver": "driver1", } acc.AssertContainsTaggedFields(t, pluginName, expectedFieldsEth1, expectedTagsEth1) expectedFieldsEth2 := toStringMapInterface(interfaceMap["eth2"].Stat) expectedTagsEth2 := map[string]string{ "interface": "eth2", "driver": "driver1", } acc.AssertContainsTaggedFields(t, pluginName, expectedFieldsEth2, expectedTagsEth2) } func TestGatherIncludeInterfaces(t *testing.T) { setup() var acc testutil.Accumulator command.InterfaceInclude = append(command.InterfaceInclude, "eth1") err := command.Gather(&acc) assert.NoError(t, err) assert.Len(t, acc.Metrics, 1) // Should contain eth1 expectedFieldsEth1 := toStringMapInterface(interfaceMap["eth1"].Stat) expectedTagsEth1 := map[string]string{ "interface": "eth1", "driver": "driver1", } acc.AssertContainsTaggedFields(t, pluginName, expectedFieldsEth1, expectedTagsEth1) // Should not contain eth2 expectedFieldsEth2 := toStringMapInterface(interfaceMap["eth2"].Stat) expectedTagsEth2 := map[string]string{ "interface": "eth2", "driver": "driver1", } acc.AssertDoesNotContainsTaggedFields(t, pluginName, expectedFieldsEth2, expectedTagsEth2) } func TestGatherIgnoreInterfaces(t *testing.T) { setup() var acc testutil.Accumulator command.InterfaceExclude = append(command.InterfaceExclude, "eth1") err := command.Gather(&acc) assert.NoError(t, err) assert.Len(t, acc.Metrics, 1) // Should not contain eth1 expectedFieldsEth1 := toStringMapInterface(interfaceMap["eth1"].Stat) expectedTagsEth1 := map[string]string{ "interface": "eth1", "driver": "driver1", } acc.AssertDoesNotContainsTaggedFields(t, pluginName, expectedFieldsEth1, expectedTagsEth1) // Should contain eth2 expectedFieldsEth2 := toStringMapInterface(interfaceMap["eth2"].Stat) expectedTagsEth2 := map[string]string{ "interface": "eth2", "driver": "driver1", } acc.AssertContainsTaggedFields(t, pluginName, expectedFieldsEth2, expectedTagsEth2) }