Skip to content

Commit

Permalink
feat(condition): Add Number Greater Than Inspector (#183)
Browse files Browse the repository at this point in the history
* feat(condition): Add Number Greater Than Inspector

* refactor: Vars, Tests

* build(config): Add Number Greater Than Inspector

* fix: Add to Factory

* refactor: Add nolint for gocyclo
  • Loading branch information
jshlbrd committed Jun 21, 2024
1 parent b271cae commit ff966ba
Show file tree
Hide file tree
Showing 6 changed files with 242 additions and 1 deletion.
11 changes: 11 additions & 0 deletions build/config/substation.libsonnet
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,17 @@
},
num: $.condition.number,
number: {
default: {
object: $.config.object,
value: null,
},
gt(settings={}): $.condition.number.greater_than(settings=settings),
greater_than(settings={}): {
local default = $.condition.number.default,

type: 'number_greater_than',
settings: std.prune(std.mergePatch(default, $.helpers.abbv(settings))),
},
bitwise: {
and(settings={}): {
local default = {
Expand Down
5 changes: 5 additions & 0 deletions build/config/substation_test.jsonnet
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@ local transform = sub.transform.object.copy(settings={ obj: { src: src, trg: trg
local inspector = sub.condition.format.json();

{
condition: {
number: {
greater_than: sub.condition.number.greater_than({obj: {src: src}, value: 1}),
}
},
transform: {
send: {
http: {
Expand Down
4 changes: 3 additions & 1 deletion condition/condition.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ type inspector interface {
}

// newInspector returns a configured Inspector from an Inspector configuration.
func newInspector(ctx context.Context, cfg config.Config) (inspector, error) { //nolint: cyclop // ignore cyclomatic complexity
func newInspector(ctx context.Context, cfg config.Config) (inspector, error) { //nolint: cyclop, gocyclo // ignore cyclomatic complexity
switch cfg.Type {
// Format inspectors.
case "format_mime":
Expand Down Expand Up @@ -58,6 +58,8 @@ func newInspector(ctx context.Context, cfg config.Config) (inspector, error) { /
case "network_ip_valid":
return newNetworkIPValid(ctx, cfg)
// Number inspectors.
case "number_greater_than":
return newNumberGreaterThan(ctx, cfg)
case "number_bitwise_and":
return newNumberBitwiseAND(ctx, cfg)
case "number_bitwise_or":
Expand Down
11 changes: 11 additions & 0 deletions condition/number.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,3 +49,14 @@ func numberLengthMeasurement(b []byte, measurement string) int {
return len(b)
}
}

type numberConfig struct {
// Value used for comparison during inspection.
Value float64 `json:"value"`

Object iconfig.Object `json:"object"`
}

func (c *numberConfig) Decode(in interface{}) error {
return iconfig.Decode(in, c)
}
54 changes: 54 additions & 0 deletions condition/number_greater_than.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package condition

import (
"context"
"encoding/json"
"strconv"

"github.com/brexhq/substation/config"
"github.com/brexhq/substation/message"
)

func newNumberGreaterThan(_ context.Context, cfg config.Config) (*numberGreaterThan, error) {
conf := numberConfig{}
if err := conf.Decode(cfg.Settings); err != nil {
return nil, err
}

insp := numberGreaterThan{
conf: conf,
}

return &insp, nil
}

type numberGreaterThan struct {
conf numberConfig
}

func (insp *numberGreaterThan) Inspect(ctx context.Context, msg *message.Message) (output bool, err error) {
if msg.IsControl() {
return false, nil
}

if insp.conf.Object.SourceKey == "" {
f, err := strconv.ParseFloat(string(msg.Data()), 64)
if err != nil {
return false, err
}

return insp.match(f), nil
}

v := msg.GetValue(insp.conf.Object.SourceKey)
return insp.match(v.Float()), nil
}

func (c *numberGreaterThan) match(f float64) bool {
return f > c.conf.Value
}

func (c *numberGreaterThan) String() string {
b, _ := json.Marshal(c.conf)
return string(b)
}
158 changes: 158 additions & 0 deletions condition/number_greater_than_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
package condition

import (
"context"
"testing"

"github.com/brexhq/substation/config"
"github.com/brexhq/substation/message"
)

var _ inspector = &numberGreaterThan{}

var numberGreaterThanTests = []struct {
name string
cfg config.Config
test []byte
expected bool
}{
// Integers
{
"pass",
config.Config{
Settings: map[string]interface{}{
"object": map[string]interface{}{
"source_key": "foo",
},
"value": 1,
},
},
[]byte(`{"foo":10}`),
true,
},
{
"pass",
config.Config{
Settings: map[string]interface{}{
"value": 1,
},
},
[]byte(`10`),
true,
},
{
"fail",
config.Config{
Settings: map[string]interface{}{
"object": map[string]interface{}{
"source_key": "foo",
},
"value": 10,
},
},
[]byte(`{"foo":1}`),
false,
},
{
"fail",
config.Config{
Settings: map[string]interface{}{
"value": 10,
},
},
[]byte(`1`),
false,
},
// Floats
{
"pass",
config.Config{
Settings: map[string]interface{}{
"value": 1,
},
},
[]byte(`1.5`),
true,
},
{
"pass",
config.Config{
Settings: map[string]interface{}{
"value": 1.1,
},
},
[]byte(`1.5`),
true,
},
{
"fail",
config.Config{
Settings: map[string]interface{}{
"object": map[string]interface{}{
"source_key": "foo",
},
"value": 1.5,
},
},
[]byte(`{"foo":1.1}`),
false,
},
{
"fail",
config.Config{
Settings: map[string]interface{}{
"value": 1.5,
},
},
[]byte(`1`),
false,
},
}

func TestNumberGreaterThan(t *testing.T) {
ctx := context.TODO()

for _, test := range numberGreaterThanTests {
t.Run(test.name, func(t *testing.T) {
message := message.New().SetData(test.test)
insp, err := newNumberGreaterThan(ctx, test.cfg)
if err != nil {
t.Fatal(err)
}

check, err := insp.Inspect(ctx, message)
if err != nil {
t.Error(err)
}

if test.expected != check {
t.Errorf("expected %v, got %v", test.expected, check)
t.Errorf("settings: %+v", test.cfg)
t.Errorf("test: %+v", string(test.test))
}
})
}
}

func benchmarkNumberGreaterThan(b *testing.B, insp *numberGreaterThan, message *message.Message) {
ctx := context.TODO()
for i := 0; i < b.N; i++ {
_, _ = insp.Inspect(ctx, message)
}
}

func BenchmarkNumberGreaterThan(b *testing.B) {
for _, test := range numberGreaterThanTests {
insp, err := newNumberGreaterThan(context.TODO(), test.cfg)
if err != nil {
b.Fatal(err)
}

b.Run(test.name,
func(b *testing.B) {
message := message.New().SetData(test.test)
benchmarkNumberGreaterThan(b, insp, message)
},
)
}
}

0 comments on commit ff966ba

Please sign in to comment.