From 9274a93511a65ac398134a6d70f1e64061e13397 Mon Sep 17 00:00:00 2001 From: Adrian Lopez Date: Thu, 4 Feb 2021 17:52:05 +0100 Subject: [PATCH] POC improve testing Use an Interface() to avoid having to create a fake snmp server. This Interface() is implemented to be used with gosnmp and mocked for the test. --- pkg/data/measurement/measurement.go | 54 +++++++++++++---- pkg/data/measurement/measurement_test.go | 77 ++++++++++++++++-------- 2 files changed, 95 insertions(+), 36 deletions(-) diff --git a/pkg/data/measurement/measurement.go b/pkg/data/measurement/measurement.go index 9f380a34..e0aa11e8 100644 --- a/pkg/data/measurement/measurement.go +++ b/pkg/data/measurement/measurement.go @@ -50,15 +50,47 @@ type Measurement struct { FilterCfg *config.MeasFilterCfg Filter filter.Filter log *logrus.Logger - snmpClient *gosnmp.GoSNMP + snmpClient SNMPClient DisableBulk bool `json:"-"` GetData func() (int64, int64, int64, error) `json:"-"` Walk func(string, gosnmp.WalkFunc) error `json:"-"` MultiIndexMeas []*Measurement } +type SNMPClient interface { + Version() gosnmp.SnmpVersion + Walk() func(rootOid string, walkFn gosnmp.WalkFunc) error + BulkWalk() func(rootOid string, walkFn gosnmp.WalkFunc) error + Target() string + Get(oids []string) (result *gosnmp.SnmpPacket, err error) +} + +type GoSNMPConverter struct { + s *gosnmp.GoSNMP +} + +func (g *GoSNMPConverter) Version() gosnmp.SnmpVersion { + return g.s.Version +} + +func (g *GoSNMPConverter) Walk() func(rootOid string, walkFn gosnmp.WalkFunc) error { + return g.s.Walk +} + +func (g *GoSNMPConverter) BulkWalk() func(rootOid string, walkFn gosnmp.WalkFunc) error { + return g.s.BulkWalk +} + +func (g *GoSNMPConverter) Target() string { + return g.s.Target +} + +func (g *GoSNMPConverter) Get(oids []string) (result *gosnmp.SnmpPacket, err error) { + return g.s.Get(oids) +} + //New creates object with config , log + goSnmp client -func New(c *config.MeasurementCfg, l *logrus.Logger, cli *gosnmp.GoSNMP, db bool) (*Measurement, error) { +func New(c *config.MeasurementCfg, l *logrus.Logger, cli SNMPClient, db bool) (*Measurement, error) { m := &Measurement{ID: c.ID, MName: c.Name, cfg: c, log: l, snmpClient: cli, DisableBulk: db} err := m.Init() return m, err @@ -86,10 +118,10 @@ func (m *Measurement) Init() error { // If GetMode is multiindex, we can reuse a simple measurement to init each one and get all funcions...? switch { - case m.snmpClient.Version == gosnmp.Version1 || m.DisableBulk: - m.Walk = m.snmpClient.Walk + case m.snmpClient.Version() == gosnmp.Version1 || m.DisableBulk: + m.Walk = m.snmpClient.Walk() default: - m.Walk = m.snmpClient.BulkWalk + m.Walk = m.snmpClient.BulkWalk() } if m.cfg.GetMode == "indexed_multiple" { @@ -356,15 +388,15 @@ func (m *Measurement) LoadMultiIndex() error { } // SetSnmpClient set a GoSNMP client to the Measurement -func (m *Measurement) SetSnmpClient(cli *gosnmp.GoSNMP) { +func (m *Measurement) SetSnmpClient(cli SNMPClient) { m.snmpClient = cli switch { - case m.snmpClient.Version == gosnmp.Version1 || m.DisableBulk: - m.Walk = m.snmpClient.Walk + case m.snmpClient.Version() == gosnmp.Version1 || m.DisableBulk: + m.Walk = m.snmpClient.Walk() default: - m.Walk = m.snmpClient.BulkWalk + m.Walk = m.snmpClient.BulkWalk() } } @@ -610,7 +642,7 @@ func (m *Measurement) SnmpWalkData() (int64, int64, int64, error) { for _, v := range m.cfg.FieldMetric { if err := m.Walk(v.BaseOID, setRawData); err != nil { - m.Errorf("SNMP WALK (%s) for OID (%s) get error: %s\n", m.snmpClient.Target, v.BaseOID, err) + m.Errorf("SNMP WALK (%s) for OID (%s) get error: %s\n", m.snmpClient.Target(), v.BaseOID, err) errors += int64(m.MetricTable.Len()) } } @@ -749,7 +781,7 @@ func (m *Measurement) SnmpGetData() (int64, int64, int64, error) { pkt, err := m.snmpClient.Get(m.snmpOids[i:end]) if err != nil { m.Debugf("selected OIDS %+v", m.snmpOids[i:end]) - m.Errorf("SNMP (%s) for OIDs (%d/%d) get error: %s\n", m.snmpClient.Target, i, end, err) + m.Errorf("SNMP (%s) for OIDs (%d/%d) get error: %s\n", m.snmpClient.Target(), i, end, err) errs++ continue } diff --git a/pkg/data/measurement/measurement_test.go b/pkg/data/measurement/measurement_test.go index 5566a41f..dc153ea7 100644 --- a/pkg/data/measurement/measurement_test.go +++ b/pkg/data/measurement/measurement_test.go @@ -4,7 +4,6 @@ import ( "bytes" "fmt" "sort" - "time" "github.com/gosnmp/gosnmp" "github.com/sirupsen/logrus" @@ -87,6 +86,54 @@ func GetOutputInfluxMetrics(m *Measurement) { // 3.- SNMP CLIENT SETUP // 4.- METRICMAP SETUP // 5.- MEASUREMENT CONFIG SETUP +// +type MockSNMP struct { + Listen string + Want []gosnmp.SnmpPDU +} + +func (m *MockSNMP) Version() gosnmp.SnmpVersion { + return gosnmp.Version1 +} + +func (m *MockSNMP) Walk() func(rootOid string, walkFn gosnmp.WalkFunc) error { + return func(rootOid string, walkFn gosnmp.WalkFunc) error { + return nil + } +} + +func (m *MockSNMP) BulkWalk() func(rootOid string, walkFn gosnmp.WalkFunc) error { + return func(rootOid string, walkFn gosnmp.WalkFunc) error { + return nil + } +} + +func (m *MockSNMP) Target() string { + return "target" +} + +func (m *MockSNMP) Get(oids []string) (result *gosnmp.SnmpPacket, err error) { + vars := []gosnmp.SnmpPDU{} + + for _, o := range oids { + for _, v := range m.Want { + if v.Name == o { + vars = append(vars, gosnmp.SnmpPDU{ + Name: v.Name, + Type: v.Type, + Value: v.Value, + }) + } + } + + } + + pkt := gosnmp.SnmpPacket{ + Variables: vars, + } + + return &pkt, nil +} func Example_Measurement_GetMode_Value() { @@ -100,7 +147,7 @@ func Example_Measurement_GetMode_Value() { // 2.- MOCK SERVER SETUP - s := &mock.SnmpServer{ + s := &MockSNMP{ Listen: "127.0.0.1:1161", Want: []gosnmp.SnmpPDU{ {Name: ".1.1.1", Type: gosnmp.Integer, Value: int(51)}, @@ -114,30 +161,8 @@ func Example_Measurement_GetMode_Value() { }, } - err := s.Start() - if err != nil { - l.Errorf("error on start snmp mock server: %s", err) - return - } - defer s.Stop() - // 3.- SNMP CLIENT SETUP - cli := &gosnmp.GoSNMP{ - Target: "127.0.0.1", - Port: 1161, - Version: gosnmp.Version2c, - Community: "test1", - Timeout: 5 * time.Second, - Retries: 0, - Logger: l, - } - err = cli.Connect() - if err != nil { - l.Fatalf("Connect() err: %v", err) - } - defer cli.Conn.Close() - // 4.- METRICMAP SETUP metrics := map[string]*config.SnmpMetricCfg{ @@ -191,7 +216,7 @@ func Example_Measurement_GetMode_Value() { // 6.- MEASUREMENT ENGINE SETUP - m, err := New(cfg, l, cli, false) + m, err := New(cfg, l, s, false) if err != nil { l.Errorf("Can not create measurement %s", err) return @@ -215,6 +240,7 @@ func Example_Measurement_GetMode_Value() { } +/* func Example_Measurement_GetMode_Indexed() { // 1.- SETUP LOGGER @@ -3040,3 +3066,4 @@ func Example_Measurement_Indexed_Multi_Indirect_STRINGEVAL() { // Measurement:interfaces_data Tags:{ portName:eth1 } Field:output ValueType:int64 Value:21 } +*/