Convert snmp_trap_test.go to table test (#6803)

Add a test for v1 generic trap.  Add missing leading period in v1 generic trap oid.
This commit is contained in:
reimda 2019-12-17 15:12:42 -07:00 committed by GitHub
parent 2beb79969a
commit 99279e6461
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 268 additions and 263 deletions

View File

@ -172,7 +172,7 @@ func makeTrapHandler(s *SnmpTrap) handler {
var trapOid string var trapOid string
if packet.GenericTrap >= 0 && packet.GenericTrap < 6 { if packet.GenericTrap >= 0 && packet.GenericTrap < 6 {
trapOid = "1.3.6.1.6.3.1.1.5." + strconv.Itoa(packet.GenericTrap+1) trapOid = ".1.3.6.1.6.3.1.1.5." + strconv.Itoa(packet.GenericTrap+1)
} else if packet.GenericTrap == 6 { } else if packet.GenericTrap == 6 {
trapOid = packet.Enterprise + ".0." + strconv.Itoa(packet.SpecificTrap) trapOid = packet.Enterprise + ".0." + strconv.Itoa(packet.SpecificTrap)
} }

View File

@ -4,6 +4,7 @@ import (
"fmt" "fmt"
"net" "net"
"strconv" "strconv"
"strings"
"testing" "testing"
"time" "time"
@ -35,11 +36,15 @@ func TestLoad(t *testing.T) {
require.Equal(t, "coldStart", e.oidText) require.Equal(t, "coldStart", e.oidText)
} }
func sendTrap(t *testing.T, port uint16) (sentTimestamp uint32) { func fakeExecCmd(_ internal.Duration, x string, y ...string) ([]byte, error) {
return nil, fmt.Errorf("mock " + x + " " + strings.Join(y, " "))
}
func sendTrap(t *testing.T, port uint16, now uint32, trap gosnmp.SnmpTrap, version gosnmp.SnmpVersion) {
s := &gosnmp.GoSNMP{ s := &gosnmp.GoSNMP{
Port: port, Port: port,
Community: "public", Community: "public",
Version: gosnmp.Version2c, Version: version,
Timeout: time.Duration(2) * time.Second, Timeout: time.Duration(2) * time.Second,
Retries: 3, Retries: 3,
MaxOids: gosnmp.MaxOids, MaxOids: gosnmp.MaxOids,
@ -52,283 +57,283 @@ func sendTrap(t *testing.T, port uint16) (sentTimestamp uint32) {
} }
defer s.Conn.Close() defer s.Conn.Close()
// If the first pdu isn't type TimeTicks, gosnmp.SendTrap() will
// prepend one with time.Now(). The time value is part of the
// plugin output so we need to keep track of it and verify it
// later.
now := uint32(time.Now().Unix())
timePdu := gosnmp.SnmpPDU{
Name: ".1.3.6.1.2.1.1.3.0",
Type: gosnmp.TimeTicks,
Value: now,
}
pdu := gosnmp.SnmpPDU{
Name: ".1.3.6.1.6.3.1.1.4.1.0", // SNMPv2-MIB::snmpTrapOID.0
Type: gosnmp.ObjectIdentifier,
Value: ".1.3.6.1.6.3.1.1.5.1", // coldStart
}
trap := gosnmp.SnmpTrap{
Variables: []gosnmp.SnmpPDU{
timePdu,
pdu,
},
}
_, err = s.SendTrap(trap) _, err = s.SendTrap(trap)
if err != nil { if err != nil {
t.Errorf("SendTrap() err: %v", err) t.Errorf("SendTrap() err: %v", err)
} }
return now
} }
func TestReceiveTrap(t *testing.T) { func TestReceiveTrap(t *testing.T) {
// We would prefer to specify port 0 and let the network stack var now uint32
// choose an unused port for us but TrapListener doesn't have a now = 123123123
// way to return the autoselected port. Instead, we'll use an
// unusual port and hope it's unused.
const port = 12399
var fakeTime = time.Now()
// hook into the trap handler so the test knows when the trap has var fakeTime time.Time
// been received fakeTime = time.Unix(456456456, 456)
received := make(chan int)
wrap := func(f handler) handler { type entry struct {
return func(p *gosnmp.SnmpPacket, a *net.UDPAddr) { oid string
f(p, a) e mibEntry
received <- 0
}
} }
// set up the service input plugin // If the first pdu isn't type TimeTicks, gosnmp.SendTrap() will
s := &SnmpTrap{ // prepend one with time.Now()
ServiceAddress: "udp://:" + strconv.Itoa(port), var tests = []struct {
makeHandlerWrapper: wrap, name string
timeFunc: func() time.Time {
return fakeTime // send
version gosnmp.SnmpVersion
trap gosnmp.SnmpTrap // include pdus
// recieve
entries []entry
metrics []telegraf.Metric
}{
//ordinary v2c coldStart trap
{
name: "v2c coldStart",
version: gosnmp.Version2c,
trap: gosnmp.SnmpTrap{
Variables: []gosnmp.SnmpPDU{
{
Name: ".1.3.6.1.2.1.1.3.0",
Type: gosnmp.TimeTicks,
Value: now,
},
{
Name: ".1.3.6.1.6.3.1.1.4.1.0", // SNMPv2-MIB::snmpTrapOID.0
Type: gosnmp.ObjectIdentifier,
Value: ".1.3.6.1.6.3.1.1.5.1", // coldStart
},
},
},
entries: []entry{
{
oid: ".1.3.6.1.6.3.1.1.4.1.0",
e: mibEntry{
"SNMPv2-MIB",
"snmpTrapOID.0",
},
},
{
oid: ".1.3.6.1.6.3.1.1.5.1",
e: mibEntry{
"SNMPv2-MIB",
"coldStart",
},
},
{
oid: ".1.3.6.1.2.1.1.3.0",
e: mibEntry{
"UNUSED_MIB_NAME",
"sysUpTimeInstance",
},
},
},
metrics: []telegraf.Metric{
testutil.MustMetric(
"snmp_trap", // name
map[string]string{ // tags
"oid": ".1.3.6.1.6.3.1.1.5.1",
"name": "coldStart",
"mib": "SNMPv2-MIB",
"version": "2c",
"source": "127.0.0.1",
},
map[string]interface{}{ // fields
"sysUpTimeInstance": now,
},
fakeTime,
),
},
}, },
Log: testutil.Logger{}, //Check that we're not running snmptranslate to look up oids
} //when we shouldn't be. This sends and receives a valid trap
require.Nil(t, s.Init()) //but metric production should fail because the oids aren't in
var acc testutil.Accumulator //the cache and oid lookup is intentionally mocked to fail.
require.Nil(t, s.Start(&acc)) {
defer s.Stop() name: "missing oid",
version: gosnmp.Version2c,
// Preload the cache with the oids we'll use in this test so trap: gosnmp.SnmpTrap{
// snmptranslate and mibs don't need to be installed. Variables: []gosnmp.SnmpPDU{
defer s.clear() {
s.load(".1.3.6.1.6.3.1.1.4.1.0", Name: ".1.3.6.1.2.1.1.3.0",
mibEntry{ Type: gosnmp.TimeTicks,
"SNMPv2-MIB", Value: now,
"snmpTrapOID.0", },
}) {
s.load(".1.3.6.1.6.3.1.1.5.1", Name: ".1.3.6.1.6.3.1.1.4.1.0", // SNMPv2-MIB::snmpTrapOID.0
mibEntry{ Type: gosnmp.ObjectIdentifier,
"SNMPv2-MIB", Value: ".1.3.6.1.6.3.1.1.5.1", // coldStart
"coldStart", },
}) },
s.load(".1.3.6.1.2.1.1.3.0",
mibEntry{
"UNUSED_MIB_NAME",
"sysUpTimeInstance",
})
// send the trap
sentTimestamp := sendTrap(t, port)
// wait for trap to be received
select {
case <-received:
case <-time.After(2 * time.Second):
t.Fatal("timed out waiting for trap to be received")
}
// verify plugin output
expected := []telegraf.Metric{
testutil.MustMetric(
"snmp_trap", // name
map[string]string{ // tags
"oid": ".1.3.6.1.6.3.1.1.5.1",
"name": "coldStart",
"mib": "SNMPv2-MIB",
"version": "2c",
"source": "127.0.0.1",
}, },
map[string]interface{}{ // fields entries: []entry{}, //nothing in cache
"sysUpTimeInstance": sentTimestamp, metrics: []telegraf.Metric{},
},
fakeTime,
),
}
testutil.RequireMetricsEqual(t,
expected, acc.GetTelegrafMetrics(),
testutil.SortMetrics())
}
func fakeExecCmd(_ internal.Duration, _ string, _ ...string) ([]byte, error) {
return nil, fmt.Errorf("intentional failure")
}
func TestMissingOid(t *testing.T) {
// should fail even if snmptranslate is installed
const port = 12399
var fakeTime = time.Now()
received := make(chan int)
wrap := func(f handler) handler {
return func(p *gosnmp.SnmpPacket, a *net.UDPAddr) {
f(p, a)
received <- 0
}
}
s := &SnmpTrap{
ServiceAddress: "udp://:" + strconv.Itoa(port),
makeHandlerWrapper: wrap,
timeFunc: func() time.Time {
return fakeTime
}, },
Log: testutil.Logger{}, //v1 enterprise specific trap
} {
require.Nil(t, s.Init()) name: "v1 trap enterprise",
var acc testutil.Accumulator version: gosnmp.Version1,
require.Nil(t, s.Start(&acc)) trap: gosnmp.SnmpTrap{
defer s.Stop() Variables: []gosnmp.SnmpPDU{
{
// make sure the cache is empty Name: ".1.2.3.4.5",
s.clear() Type: gosnmp.OctetString,
Value: "payload",
// don't call the real snmptranslate },
s.execCmd = fakeExecCmd },
Enterprise: ".1.2.3",
_ = sendTrap(t, port) AgentAddress: "10.20.30.40",
GenericTrap: 6, // enterpriseSpecific
select { SpecificTrap: 55,
case <-received: Timestamp: uint(now),
case <-time.After(2 * time.Second): },
t.Fatal("timed out waiting for trap to be received") entries: []entry{
} {
".1.2.3.4.5",
// oid lookup should fail so we shouldn't get a metric mibEntry{
expected := []telegraf.Metric{} "valueMIB",
"valueOID",
testutil.RequireMetricsEqual(t, },
expected, acc.GetTelegrafMetrics(), },
testutil.SortMetrics()) {
} ".1.2.3.0.55",
mibEntry{
func sendV1Trap(t *testing.T, port uint16) (sentTimestamp uint) { "enterpriseMIB",
s := &gosnmp.GoSNMP{ "enterpriseOID",
Port: port, },
Community: "public", },
Version: gosnmp.Version1, },
Timeout: time.Duration(2) * time.Second, metrics: []telegraf.Metric{
Retries: 3, testutil.MustMetric(
MaxOids: gosnmp.MaxOids, "snmp_trap", // name
Target: "127.0.0.1", map[string]string{ // tags
} "oid": ".1.2.3.0.55",
"name": "enterpriseOID",
err := s.Connect() "mib": "enterpriseMIB",
if err != nil { "version": "1",
t.Fatalf("Connect() err: %v", err) "source": "127.0.0.1",
} "agent_address": "10.20.30.40",
defer s.Conn.Close() },
map[string]interface{}{ // fields
now := uint(time.Now().Unix()) "sysUpTimeInstance": uint(now),
"valueOID": "payload",
pdu := gosnmp.SnmpPDU{ },
Name: ".1.2.3.4.5", fakeTime,
Type: gosnmp.OctetString, ),
Value: "payload", },
}
trap := gosnmp.SnmpTrap{
Variables: []gosnmp.SnmpPDU{pdu},
Enterprise: ".1.2.3",
AgentAddress: "10.20.30.40",
GenericTrap: 6, // enterpriseSpecific
SpecificTrap: 55,
Timestamp: now,
}
_, err = s.SendTrap(trap)
if err != nil {
t.Fatalf("SendTrap() err: %v", err)
}
return now
}
func TestReceiveV1Trap(t *testing.T) {
const port = 12399
var fakeTime = time.Now()
received := make(chan int)
wrap := func(f handler) handler {
return func(p *gosnmp.SnmpPacket, a *net.UDPAddr) {
f(p, a)
received <- 0
}
}
s := &SnmpTrap{
ServiceAddress: "udp://:" + strconv.Itoa(port),
makeHandlerWrapper: wrap,
timeFunc: func() time.Time {
return fakeTime
}, },
Log: testutil.Logger{}, //v1 generic trap
} {
require.Nil(t, s.Init()) name: "v1 trap generic",
var acc testutil.Accumulator version: gosnmp.Version1,
require.Nil(t, s.Start(&acc)) trap: gosnmp.SnmpTrap{
defer s.Stop() Variables: []gosnmp.SnmpPDU{
{
defer s.clear() Name: ".1.2.3.4.5",
s.load(".1.2.3.4.5", Type: gosnmp.OctetString,
mibEntry{ Value: "payload",
"valueMIB", },
"valueOID", },
}) Enterprise: ".1.2.3",
s.load(".1.2.3.0.55", AgentAddress: "10.20.30.40",
mibEntry{ GenericTrap: 0, //coldStart
"enterpriseMIB", SpecificTrap: 0,
"enterpriseOID", Timestamp: uint(now),
})
sentTimestamp := sendV1Trap(t, port)
select {
case <-received:
case <-time.After(2 * time.Second):
t.Fatal("timed out waiting for trap to be received")
}
expected := []telegraf.Metric{
testutil.MustMetric(
"snmp_trap", // name
map[string]string{ // tags
"oid": ".1.2.3.0.55",
"name": "enterpriseOID",
"mib": "enterpriseMIB",
"version": "1",
"source": "127.0.0.1",
"agent_address": "10.20.30.40",
}, },
map[string]interface{}{ // fields entries: []entry{
"sysUpTimeInstance": sentTimestamp, {
"valueOID": "payload", ".1.2.3.4.5",
mibEntry{
"valueMIB",
"valueOID",
},
},
{
".1.3.6.1.6.3.1.1.5.1",
mibEntry{
"coldStartMIB",
"coldStartOID",
},
},
}, },
fakeTime, metrics: []telegraf.Metric{
), testutil.MustMetric(
"snmp_trap", // name
map[string]string{ // tags
"oid": ".1.3.6.1.6.3.1.1.5.1",
"name": "coldStartOID",
"mib": "coldStartMIB",
"version": "1",
"source": "127.0.0.1",
"agent_address": "10.20.30.40",
},
map[string]interface{}{ // fields
"sysUpTimeInstance": uint(now),
"valueOID": "payload",
},
fakeTime,
),
},
},
} }
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
// We would prefer to specify port 0 and let the network
// stack choose an unused port for us but TrapListener
// doesn't have a way to return the autoselected port.
// Instead, we'll use an unusual port and hope it's
// unused.
const port = 12399
testutil.RequireMetricsEqual(t, // Hook into the trap handler so the test knows when the
expected, acc.GetTelegrafMetrics(), // trap has been received
testutil.SortMetrics()) received := make(chan int)
wrap := func(f handler) handler {
return func(p *gosnmp.SnmpPacket, a *net.UDPAddr) {
f(p, a)
received <- 0
}
}
// Set up the service input plugin
s := &SnmpTrap{
ServiceAddress: "udp://:" + strconv.Itoa(port),
makeHandlerWrapper: wrap,
timeFunc: func() time.Time {
return fakeTime
},
Log: testutil.Logger{},
}
require.Nil(t, s.Init())
var acc testutil.Accumulator
require.Nil(t, s.Start(&acc))
defer s.Stop()
// Preload the cache with the oids we'll use in this test
// so snmptranslate and mibs don't need to be installed.
for _, entry := range tt.entries {
s.load(entry.oid, entry.e)
}
// Don't look up oid with snmptranslate.
s.execCmd = fakeExecCmd
// Send the trap
sendTrap(t, port, now, tt.trap, tt.version)
// Wait for trap to be received
select {
case <-received:
case <-time.After(2 * time.Second):
t.Fatal("timed out waiting for trap to be received")
}
// Verify plugin output
testutil.RequireMetricsEqual(t,
tt.metrics, acc.GetTelegrafMetrics(),
testutil.SortMetrics())
})
}
} }