Skip to content

Commit

Permalink
feat: add boolean behavior for time objects (#24243)
Browse files Browse the repository at this point in the history
Description: Allows time comparison by enabling boolean behavior for
time objects.

Link to tracking Issue: Closes #22008

Testing: Unit tests

Documentation:

---------

Co-authored-by: Tyler Helmuth <[email protected]>
  • Loading branch information
fchikwekwe and TylerHelmuth authored Jul 14, 2023
1 parent 2b2c967 commit 983815c
Show file tree
Hide file tree
Showing 4 changed files with 89 additions and 1 deletion.
20 changes: 20 additions & 0 deletions .chloggen/feat_boolean-time.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Use this changelog template to create an entry for release notes.
# If your change doesn't affect end users, such as a test fix or a tooling change,
# you should instead start your pull request title with [chore] or use the "Skip Changelog" label.

# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix'
change_type: 'enhancement'

# The name of the component, or a single word describing the area of concern, (e.g. filelogreceiver)
component: 'pkg/ottl'

# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`).
note: 'Adds support for using boolean expressions with time objects'

# Mandatory: One or more tracking issues related to the change. You can use the PR number here if no issue exists.
issues: [22008]

# (Optional) One or more lines of additional information to render under the primary note.
# These lines will be padded with 2 spaces and then inserted directly into the document.
# Use pipe (|) for multiline entries.
subtext:
27 changes: 26 additions & 1 deletion pkg/ottl/boolean_value_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"context"
"strings"
"testing"
"time"

"github.com/stretchr/testify/assert"
"go.opentelemetry.io/collector/component/componenttest"
Expand Down Expand Up @@ -37,6 +38,16 @@ func valueFor(x any) value {
case strings.Contains(v, "ENUM"):
// if the string contains ENUM construct an EnumSymbol from it.
val.Enum = (*EnumSymbol)(ottltest.Strp(v))
case v == "time1" || v == "time2":
val.Literal = &mathExprLiteral{
Path: &Path{
Fields: []Field{
{
Name: v,
},
},
},
}
default:
val.String = ottltest.Strp(v)
}
Expand Down Expand Up @@ -76,12 +87,14 @@ func Test_newComparisonEvaluator(t *testing.T) {
WithEnumParser[any](testParseEnum),
)

JanFirst2023 := time.Date(2023, 1, 1, 0, 0, 0, 0, time.Local)

var tests = []struct {
name string
l any
r any
op string
item string
item any
want bool
}{
{name: "literals match", l: "hello", r: "hello", op: "==", want: true},
Expand All @@ -106,6 +119,18 @@ func Test_newComparisonEvaluator(t *testing.T) {
{name: "[]byte('a') < []byte('b')", l: []byte("a"), r: []byte("b"), op: "<", want: true},
{name: "nil == nil", op: "==", want: true},
{name: "nil == []byte(nil)", r: []byte(nil), op: "==", want: true},
{name: "compare equal times", l: "time1", r: "time2", op: "==", want: true, item: map[string]time.Time{"time1": JanFirst2023, "time2": JanFirst2023}},
{name: "compare unequal times", l: "time1", r: "time2", op: "==", want: false, item: map[string]time.Time{"time1": JanFirst2023, "time2": time.Date(2023, 1, 2, 0, 0, 0, 0, time.Local)}},
{name: "compare for not equal times", l: "time1", r: "time2", op: "!=", want: true, item: map[string]time.Time{"time1": JanFirst2023, "time2": time.Date(2002, 11, 2, 01, 01, 01, 01, time.Local)}},
{name: "compare for equal times using not equal", l: "time1", r: "time2", op: "!=", want: false, item: map[string]time.Time{"time1": time.Date(2002, 11, 2, 01, 01, 01, 01, time.Local), "time2": time.Date(2002, 11, 2, 01, 01, 01, 01, time.Local)}},
{name: "compare less than times", l: "time1", r: "time2", op: "<", want: true, item: map[string]time.Time{"time1": JanFirst2023, "time2": time.Date(2023, 5, 2, 01, 01, 01, 01, time.Local)}},
{name: "compare not less than times", l: "time1", r: "time2", op: "<", want: false, item: map[string]time.Time{"time1": time.Date(2023, 6, 2, 01, 01, 01, 01, time.Local), "time2": time.Date(2023, 5, 2, 01, 01, 01, 01, time.Local)}},
{name: "compare less than equal to times", l: "time1", r: "time2", op: "<=", want: true, item: map[string]time.Time{"time1": time.Date(2003, 5, 2, 01, 01, 01, 01, time.Local), "time2": time.Date(2003, 5, 2, 01, 01, 01, 01, time.Local)}},
{name: "compare not less than equal to times", l: "time1", r: "time2", op: "<=", want: false, item: map[string]time.Time{"time1": time.Date(2002, 5, 2, 01, 01, 01, 01, time.Local), "time2": time.Date(1999, 5, 2, 01, 01, 01, 01, time.Local)}},
{name: "compare not greater than equal to w/ times", l: "time1", r: "time2", op: ">=", want: false, item: map[string]time.Time{"time1": time.Date(2002, 5, 2, 01, 01, 01, 01, time.Local), "time2": time.Date(2003, 5, 2, 01, 01, 01, 01, time.Local)}},
{name: "compare greater than equal to w/ times", l: "time1", r: "time2", op: ">=", want: true, item: map[string]time.Time{"time1": time.Date(2022, 5, 2, 01, 01, 01, 01, time.Local), "time2": time.Date(2003, 5, 2, 01, 01, 01, 01, time.Local)}},
{name: "compare greater than w/ times", l: "time1", r: "time2", op: ">", want: true, item: map[string]time.Time{"time1": time.Date(2022, 5, 2, 01, 01, 01, 01, time.Local), "time2": time.Date(2003, 5, 2, 01, 01, 01, 01, time.Local)}},
{name: "compare not greater than w/ times", l: "time1", r: "time2", op: ">", want: false, item: map[string]time.Time{"time1": time.Date(2002, 3, 2, 01, 01, 01, 01, time.Local), "time2": time.Date(2003, 5, 2, 01, 01, 01, 01, time.Local)}},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
Expand Down
27 changes: 27 additions & 0 deletions pkg/ottl/compare.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ package ottl // import "github.com/open-telemetry/opentelemetry-collector-contri

import (
"bytes"
"time"

"go.uber.org/zap"
"golang.org/x/exp/constraints"
Expand Down Expand Up @@ -135,6 +136,30 @@ func (p *Parser[K]) compareFloat64(a float64, b any, op compareOp) bool {
}
}

func (p *Parser[K]) compareTime(a time.Time, b any, op compareOp) bool {
switch v := b.(type) {
case time.Time:
switch op {
case EQ:
return a.Equal(v)
case NE:
return !a.Equal(v)
case LT:
return a.Before(v)
case LTE:
return a.Before(v) || a.Equal(v)
case GTE:
return a.After(v) || a.Equal(v)
case GT:
return a.After(v)
default:
return p.invalidComparison("invalid comparison operator", op)
}
default:
return p.invalidComparison("time to non-time value", op)
}
}

// a and b are the return values from a Getter; we try to compare them
// according to the given operator.
func (p *Parser[K]) compare(a any, b any, op compareOp) bool {
Expand Down Expand Up @@ -162,6 +187,8 @@ func (p *Parser[K]) compare(a any, b any, op compareOp) bool {
return p.compare(b, nil, op)
}
return p.compareByte(v, b, op)
case time.Time:
return p.compareTime(v, b, op)
default:
// If we don't know what type it is, we can't do inequalities yet. So we can fall back to the old behavior where we just
// use Go's standard equality.
Expand Down
16 changes: 16 additions & 0 deletions pkg/ottl/parser_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"reflect"
"regexp"
"testing"
"time"

"github.com/stretchr/testify/assert"
"go.opentelemetry.io/collector/component/componenttest"
Expand Down Expand Up @@ -875,6 +876,21 @@ func testParsePath(val *Path) (GetSetter[interface{}], error) {
},
}, nil
}
if val.Fields[0].Name == "time1" || val.Fields[0].Name == "time2" {
return &StandardGetSetter[interface{}]{
Getter: func(ctx context.Context, tCtx interface{}) (interface{}, error) {
m, ok := tCtx.(map[string]time.Time)
if !ok {
return nil, fmt.Errorf("unable to convert transform context to map of strings to times")
}
return m[val.Fields[0].Name], nil
},
Setter: func(ctx context.Context, tCtx interface{}, val interface{}) error {
reflect.DeepEqual(tCtx, val)
return nil
},
}, nil
}
return nil, fmt.Errorf("bad path %v", val)
}

Expand Down

0 comments on commit 983815c

Please sign in to comment.