Skip to content

Commit

Permalink
added exclusive value filter
Browse files Browse the repository at this point in the history
  • Loading branch information
TheFireMike committed Oct 19, 2021
1 parent 6573934 commit 04cb2d6
Show file tree
Hide file tree
Showing 4 changed files with 356 additions and 16 deletions.
97 changes: 81 additions & 16 deletions internal/deviceclass/groupproperty/filter.go
Original file line number Diff line number Diff line change
Expand Up @@ -170,8 +170,8 @@ func (g *valueFilter) ApplyPropertyGroups(ctx context.Context, propertyGroups Pr
var res PropertyGroups

for _, group := range propertyGroups {
newGroup, err := filterPropertyGroupKey(ctx, group, g.value, func(a, b string) bool {
return a == b
newGroup, err := filterPropertyGroupKey(ctx, group, g.value, func(val string, key []string) (bool, bool) {
return val == key[0], len(key) == 1
})
if err != nil {
return nil, errors.Wrap(err, "failed to filter group property")
Expand All @@ -184,37 +184,102 @@ func (g *valueFilter) ApplyPropertyGroups(ctx context.Context, propertyGroups Pr

func (g *valueFilter) applySNMP(ctx context.Context, reader snmpReader) (snmpReader, error) {
var err error
reader.oids, err = filterOIDReaderKey(ctx, reader.oids, g.value, func(a, b string) bool {
return a == b
reader.oids, err = filterOIDReaderKey(ctx, reader.oids, g.value, func(val string, key []string) (bool, bool) {
return val == key[0], len(key) == 1
})
if err != nil {
return snmpReader{}, err
}
return reader, nil
}

func filterPropertyGroupKey(ctx context.Context, group propertyGroup, key []string, compareFunc func(a, b string) bool) (propertyGroup, error) {
type exclusiveValueFilter struct {
values [][]string
}

func GetExclusiveValueFilter(values [][]string) Filter {
return &exclusiveValueFilter{
values: values,
}
}

func (g *exclusiveValueFilter) CheckMatch(value []string) bool {
for _, val := range g.values {
for i, k := range value {
if i >= len(val) || k != val[i] {
continue
}
if i == len(val)-1 && k == val[i] {
return false
}
}
}
return true
}

func (g *exclusiveValueFilter) ApplyPropertyGroups(ctx context.Context, propertyGroups PropertyGroups) (PropertyGroups, error) {
var res PropertyGroups

for _, group := range propertyGroups {
newGroup := make(propertyGroup)
for _, k := range g.values {
exclusiveGroup, err := filterPropertyGroupKey(ctx, group, k, func(val string, key []string) (bool, bool) {
return !(val == key[0] && len(key) == 1), !(val == key[0])
})
if err != nil {
return nil, errors.Wrap(err, "failed to filter group property")
}
newGroup = newGroup.merge(exclusiveGroup)
}
res = append(res, newGroup)
}

return res, nil
}

func (g *exclusiveValueFilter) applySNMP(ctx context.Context, reader snmpReader) (snmpReader, error) {
res := reader
oids := make(deviceClassOIDs)
res.oids = &oids

for _, k := range g.values {
tmp, err := filterOIDReaderKey(ctx, reader.oids, k, func(val string, key []string) (bool, bool) {
return !(val == key[0] && len(key) == 1), !(val == key[0])
})
if err != nil {
return snmpReader{}, err
}

if tmpConverted, ok := tmp.(*deviceClassOIDs); ok {
oids = oids.merge(*tmpConverted)
}
}

return res, nil
}

func filterPropertyGroupKey(ctx context.Context, group propertyGroup, key []string, matcher func(string, []string) (bool, bool)) (propertyGroup, error) {
if len(key) == 0 {
return nil, errors.New("filter key is empty")
}

//copy values
groupCopy := make(propertyGroup)
for k, v := range group {
if compareFunc(k, key[0]) {
if len(key) > 1 {
if match, del := matcher(k, key); match {
if del {
log.Ctx(ctx).Debug().Str("value", k).Msg("filter matched on value in property group")
} else {
var nextGroup propertyGroup
err := nextGroup.encode(v)
if err != nil {
return nil, errors.Wrap(err, "failed to encode next filter key value to property group")
}
r, err := filterPropertyGroupKey(ctx, nextGroup, key[1:], compareFunc)
r, err := filterPropertyGroupKey(ctx, nextGroup, key[1:], matcher)
if err != nil {
return nil, err
}
groupCopy[k] = r
} else {
log.Ctx(ctx).Debug().Str("value", k).Msg("filter matched on value in property group")
}
continue
}
Expand All @@ -224,7 +289,7 @@ func filterPropertyGroupKey(ctx context.Context, group propertyGroup, key []stri
return groupCopy, nil
}

func filterOIDReaderKey(ctx context.Context, reader OIDReader, key []string, compareFunc func(a, b string) bool) (OIDReader, error) {
func filterOIDReaderKey(ctx context.Context, reader OIDReader, key []string, matcher func(string, []string) (bool, bool)) (OIDReader, error) {
if len(key) == 0 {
return nil, errors.New("filter key is empty")
}
Expand All @@ -238,15 +303,15 @@ func filterOIDReaderKey(ctx context.Context, reader OIDReader, key []string, com
//copy values
readerCopy := make(deviceClassOIDs)
for k, v := range *multipleReader {
if compareFunc(k, key[0]) {
if len(key) > 1 {
r, err := filterOIDReaderKey(ctx, v, key[1:], compareFunc)
if match, del := matcher(k, key); match {
if del {
log.Ctx(ctx).Debug().Str("value", k).Msg("filter matched on value in snmp reader")
} else {
r, err := filterOIDReaderKey(ctx, v, key[1:], matcher)
if err != nil {
return nil, err
}
readerCopy[k] = r
} else {
log.Ctx(ctx).Debug().Str("value", k).Msg("filter matched on value in snmp reader")
}
continue
}
Expand Down
220 changes: 220 additions & 0 deletions internal/deviceclass/groupproperty/filter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -462,3 +462,223 @@ func TestValueFilter_applySNMP_noMatch(t *testing.T) {

assert.Equal(t, reader, filteredGroup)
}

func TestExclusiveValueFilter_CheckMatch(t *testing.T) {
valueFilter := GetExclusiveValueFilter([][]string{{"radio", "level_in"}})

filter, ok := valueFilter.(ValueFilter)
assert.True(t, ok, "exclusive value filter is not implementing the ValueFilter interface")

assert.True(t, filter.CheckMatch([]string{"radio"}))
assert.True(t, filter.CheckMatch([]string{"ifDescr"}))
assert.True(t, filter.CheckMatch([]string{"radio", "level_out"}))
assert.False(t, filter.CheckMatch([]string{"radio", "level_in"}))
assert.False(t, filter.CheckMatch([]string{"radio", "level_in", "test"}))
}

func TestExclusiveValueFilter_ApplyPropertyGroups(t *testing.T) {
filter := GetExclusiveValueFilter([][]string{{"ifDescr"}})

groups := PropertyGroups{
propertyGroup{
"ifIndex": "1",
"ifDescr": "Ethernet #1",
"ifOperStatus": "1",
},
}

filteredGroup, err := filter.ApplyPropertyGroups(context.Background(), groups)
assert.NoError(t, err)

expected := PropertyGroups{
propertyGroup{
"ifDescr": "Ethernet #1",
},
}

assert.Equal(t, expected, filteredGroup)
}

func TestExclusiveValueFilter_ApplyPropertyGroups_multiple(t *testing.T) {
filter := GetExclusiveValueFilter([][]string{{"ifIndex"}, {"ifDescr"}})

groups := PropertyGroups{
propertyGroup{
"ifIndex": "1",
"ifDescr": "Ethernet #1",
"ifOperStatus": "1",
},
}

filteredGroup, err := filter.ApplyPropertyGroups(context.Background(), groups)
assert.NoError(t, err)

expected := PropertyGroups{
propertyGroup{
"ifIndex": "1",
"ifDescr": "Ethernet #1",
},
}

assert.Equal(t, expected, filteredGroup)
}

func TestExclusiveValueFilter_ApplyPropertyGroups_nested(t *testing.T) {
filter := GetExclusiveValueFilter([][]string{{"radio", "level_in"}})

groups := PropertyGroups{
propertyGroup{
"ifIndex": "1",
"radio": propertyGroup{
"level_in": "10",
},
},
}

filteredGroup, err := filter.ApplyPropertyGroups(context.Background(), groups)
assert.NoError(t, err)

expected := PropertyGroups{
propertyGroup{
"radio": propertyGroup{
"level_in": "10",
},
},
}

assert.Equal(t, expected, filteredGroup)
}

func TestExclusiveValueFilter_ApplyPropertyGroups_multipleNested(t *testing.T) {
filter := GetExclusiveValueFilter([][]string{{"radio", "level_in"}, {"radio", "level_out"}})

groups := PropertyGroups{
propertyGroup{
"ifIndex": "1",
"radio": propertyGroup{
"level_in": "10",
"level_out": "10",
"max_bitrate_in": "100000",
},
},
}

filteredGroup, err := filter.ApplyPropertyGroups(context.Background(), groups)
assert.NoError(t, err)

expected := PropertyGroups{
propertyGroup{
"radio": propertyGroup{
"level_in": "10",
"level_out": "10",
},
},
}

assert.Equal(t, expected, filteredGroup)
}

func TestExclusiveValueFilter_applySNMP(t *testing.T) {
filter := GetExclusiveValueFilter([][]string{{"ifDescr"}})

reader := snmpReader{
oids: &deviceClassOIDs{
"ifDescr": &deviceClassOID{
SNMPGetConfiguration: network.SNMPGetConfiguration{
OID: "1",
},
},
"ifOperStatus": &deviceClassOID{
SNMPGetConfiguration: network.SNMPGetConfiguration{
OID: "2",
},
},
},
}

filteredGroup, err := filter.applySNMP(context.Background(), reader)
assert.NoError(t, err)

expected := snmpReader{
oids: &deviceClassOIDs{
"ifDescr": &deviceClassOID{
SNMPGetConfiguration: network.SNMPGetConfiguration{
OID: "1",
},
},
},
}

assert.Equal(t, expected, filteredGroup)
}

func TestExclusiveValueFilter_applySNMP_nested(t *testing.T) {
filter := GetExclusiveValueFilter([][]string{{"radio", "level_in"}})

reader := snmpReader{
oids: &deviceClassOIDs{
"ifDescr": &deviceClassOID{
SNMPGetConfiguration: network.SNMPGetConfiguration{
OID: "1",
},
},
"radio": &deviceClassOIDs{
"level_in": &deviceClassOID{
SNMPGetConfiguration: network.SNMPGetConfiguration{
OID: "2",
},
},
"level_out": &deviceClassOID{
SNMPGetConfiguration: network.SNMPGetConfiguration{
OID: "3",
},
},
},
},
}

filteredGroup, err := filter.applySNMP(context.Background(), reader)
assert.NoError(t, err)

expected := snmpReader{
oids: &deviceClassOIDs{
"radio": &deviceClassOIDs{
"level_in": &deviceClassOID{
SNMPGetConfiguration: network.SNMPGetConfiguration{
OID: "2",
},
},
},
},
}

assert.Equal(t, expected, filteredGroup)
}

func TestExclusiveValueFilter_applySNMP_noMatch(t *testing.T) {
filter := GetExclusiveValueFilter([][]string{{"ifSpeed"}})

reader := snmpReader{
oids: &deviceClassOIDs{
"ifDescr": &deviceClassOID{
SNMPGetConfiguration: network.SNMPGetConfiguration{
OID: "1",
},
},
"ifOperStatus": &deviceClassOID{
SNMPGetConfiguration: network.SNMPGetConfiguration{
OID: "2",
},
},
},
}

filteredGroup, err := filter.applySNMP(context.Background(), reader)
assert.NoError(t, err)

expected := snmpReader{
oids: &deviceClassOIDs{},
}

assert.Equal(t, expected, filteredGroup)
}
Loading

0 comments on commit 04cb2d6

Please sign in to comment.