Skip to content

Commit e317204

Browse files
author
Lennart Elsen
committed
Implement isBool and add to list of supported functions
Also updates the changelog
1 parent eb320a1 commit e317204

File tree

6 files changed

+248
-0
lines changed

6 files changed

+248
-0
lines changed
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# Use this changelog template to create an entry for release notes.
2+
3+
# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix'
4+
change_type: enhancement
5+
6+
# The name of the component, or a single word describing the area of concern, (e.g. filelogreceiver)
7+
component: pkg/ottl
8+
9+
# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`).
10+
note: The IsBool function is now available to OTTL
11+
12+
# Mandatory: One or more tracking issues related to the change. You can use the PR number here if no issue exists.
13+
issues: [27897]
14+
15+
# (Optional) One or more lines of additional information to render under the primary note.
16+
# These lines will be padded with 2 spaces and then inserted directly into the document.
17+
# Use pipe (|) for multiline entries.
18+
19+
# If your change doesn't affect end users or the exported elements of any package,
20+
# you should instead start your pull request title with [chore] or use the "Skip Changelog" label.
21+
# Optional: The change log or logs in which this entry should be included.
22+
# e.g. '[user]' or '[user, api]'
23+
# Include 'user' if the change is relevant to end users.
24+
# Include 'api' if there is a change to a library API.
25+
# Default: '[user]'
26+
change_logs: [user]

pkg/ottl/expression.go

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,43 @@ func (t TypeError) Error() string {
142142
return string(t)
143143
}
144144

145+
// BoolGetter is a Getter than must return a bool.
146+
type BoolGetter[K any] interface {
147+
// Get retrieves a bool value.
148+
Get(ctx context.Context, tCtx K) (bool, error)
149+
}
150+
151+
// StandardBoolGetter is a basic implementation of BoolGetter
152+
type StandardBoolGetter[K any] struct {
153+
Getter func(ctx context.Context, tCtx K) (interface{}, error)
154+
}
155+
156+
const boolExpectMsg = "expected bool but got"
157+
158+
// Get retrieves a bool value.
159+
// If the value is not a bool a new TypeError is returned.
160+
// If there is an error getting the value it will be returned.
161+
func (g StandardBoolGetter[K]) Get(ctx context.Context, tCtx K) (bool, error) {
162+
val, err := g.Getter(ctx, tCtx)
163+
if err != nil {
164+
return false, fmt.Errorf("error getting value in %T: %w", g, err)
165+
}
166+
if val == nil {
167+
return false, TypeError(boolExpectMsg + " nil")
168+
}
169+
switch v := val.(type) {
170+
case bool:
171+
return v, nil
172+
case pcommon.Value:
173+
if v.Type() == pcommon.ValueTypeBool {
174+
return v.Bool(), nil
175+
}
176+
return false, TypeError(fmt.Sprintf("%s %v", boolExpectMsg, v.Type()))
177+
default:
178+
return false, TypeError(fmt.Sprintf("%s %T", boolExpectMsg, val))
179+
}
180+
}
181+
145182
// StringGetter is a Getter that must return a string.
146183
type StringGetter[K any] interface {
147184
// Get retrieves a string value.

pkg/ottl/expression_test.go

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -614,6 +614,70 @@ func Test_exprGetter_Get_Invalid(t *testing.T) {
614614
}
615615
}
616616

617+
func Test_StandardBoolGetter(t *testing.T) {
618+
tests := []struct {
619+
name string
620+
getter StandardBoolGetter[interface{}]
621+
want interface{}
622+
valid bool
623+
expectedErrorMsg string
624+
}{
625+
{
626+
name: "bool type",
627+
getter: StandardBoolGetter[interface{}]{
628+
Getter: func(ctx context.Context, tCtx interface{}) (interface{}, error) {
629+
return true, nil
630+
},
631+
},
632+
want: true,
633+
valid: true,
634+
},
635+
{
636+
name: "ValueTypeBool type",
637+
getter: StandardBoolGetter[interface{}]{
638+
Getter: func(ctx context.Context, tCtx interface{}) (interface{}, error) {
639+
return pcommon.NewValueBool(true), nil
640+
},
641+
},
642+
want: true,
643+
valid: true,
644+
},
645+
{
646+
name: "Incorrect type",
647+
getter: StandardBoolGetter[interface{}]{
648+
Getter: func(ctx context.Context, tCtx interface{}) (interface{}, error) {
649+
return "str", nil
650+
},
651+
},
652+
valid: false,
653+
expectedErrorMsg: boolExpectMsg + " string",
654+
},
655+
{
656+
name: "nil",
657+
getter: StandardBoolGetter[interface{}]{
658+
Getter: func(ctx context.Context, tCtx interface{}) (interface{}, error) {
659+
return nil, nil
660+
},
661+
},
662+
valid: false,
663+
expectedErrorMsg: boolExpectMsg + " nil",
664+
},
665+
}
666+
667+
for _, tt := range tests {
668+
t.Run(tt.name, func(t *testing.T) {
669+
val, err := tt.getter.Get(context.Background(), nil)
670+
if tt.valid {
671+
assert.NoError(t, err)
672+
assert.Equal(t, tt.want, val)
673+
} else {
674+
assert.IsType(t, TypeError(""), err)
675+
assert.EqualError(t, err, tt.expectedErrorMsg)
676+
}
677+
})
678+
}
679+
}
680+
617681
func Test_StandardStringGetter(t *testing.T) {
618682
tests := []struct {
619683
name string

pkg/ottl/ottlfuncs/func_is_bool.go

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
// Copyright The OpenTelemetry Authors
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
package ottlfuncs // import "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/ottl/ottlfuncs"
5+
6+
import (
7+
"context"
8+
"fmt"
9+
10+
"github.com/open-telemetry/opentelemetry-collector-contrib/pkg/ottl"
11+
)
12+
13+
type IsBoolArguments[K any] struct {
14+
Target ottl.BoolGetter[K]
15+
}
16+
17+
func NewIsBoolFactory[K any]() ottl.Factory[K] {
18+
return ottl.NewFactory("IsBool", &IsBoolArguments[K]{}, createIsBoolFunction[K])
19+
}
20+
21+
func createIsBoolFunction[K any](_ ottl.FunctionContext, oArgs ottl.Arguments) (ottl.ExprFunc[K], error) {
22+
args, ok := oArgs.(*IsBoolArguments[K])
23+
24+
if !ok {
25+
return nil, fmt.Errorf("IsBoolFactory args must be of type *IsBoolArguments[K]")
26+
}
27+
28+
return isBool(args.Target), nil
29+
}
30+
31+
// nolint:errorlint
32+
func isBool[K any](target ottl.BoolGetter[K]) ottl.ExprFunc[K] {
33+
return func(ctx context.Context, tCtx K) (interface{}, error) {
34+
_, err := target.Get(ctx, tCtx)
35+
36+
// Use type assertion because we don't want to check wrapped errors
37+
switch err.(type) {
38+
case ottl.TypeError:
39+
return false, nil
40+
case nil:
41+
return true, nil
42+
default:
43+
return false, err
44+
}
45+
}
46+
}
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
// Copyright The OpenTelemetry Authors
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
package ottlfuncs
5+
6+
import (
7+
"context"
8+
"testing"
9+
10+
"github.com/stretchr/testify/assert"
11+
"go.opentelemetry.io/collector/pdata/pcommon"
12+
13+
"github.com/open-telemetry/opentelemetry-collector-contrib/pkg/ottl"
14+
)
15+
16+
func Test_IsBool(t *testing.T) {
17+
tests := []struct {
18+
name string
19+
value interface{}
20+
expected bool
21+
}{
22+
{
23+
name: "bool",
24+
value: true,
25+
expected: true,
26+
},
27+
{
28+
name: "ValueTypeBool",
29+
value: pcommon.NewValueBool(true),
30+
expected: true,
31+
},
32+
{
33+
name: "not bool",
34+
value: 1,
35+
expected: false,
36+
},
37+
{
38+
name: "ValueTypeSlice",
39+
value: pcommon.NewValueSlice(),
40+
expected: false,
41+
},
42+
{
43+
name: "nil",
44+
value: nil,
45+
expected: false,
46+
},
47+
}
48+
for _, tt := range tests {
49+
t.Run(tt.name, func(t *testing.T) {
50+
exprFunc := isBool[any](&ottl.StandardBoolGetter[any]{
51+
Getter: func(context.Context, interface{}) (interface{}, error) {
52+
return tt.value, nil
53+
},
54+
})
55+
result, err := exprFunc(context.Background(), nil)
56+
assert.NoError(t, err)
57+
assert.Equal(t, tt.expected, result)
58+
})
59+
}
60+
}
61+
62+
// nolint:errorlint
63+
func Test_IsBool_Error(t *testing.T) {
64+
exprFunc := isBool[any](&ottl.StandardBoolGetter[any]{
65+
Getter: func(context.Context, interface{}) (interface{}, error) {
66+
return nil, ottl.TypeError("")
67+
},
68+
})
69+
result, err := exprFunc(context.Background(), nil)
70+
assert.Equal(t, false, result)
71+
assert.Error(t, err)
72+
_, ok := err.(ottl.TypeError)
73+
assert.False(t, ok)
74+
}

pkg/ottl/ottlfuncs/functions.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ func converters[K any]() []ottl.Factory[K] {
4242
NewFnvFactory[K](),
4343
NewHoursFactory[K](),
4444
NewIntFactory[K](),
45+
NewIsBoolFactory[K](),
4546
NewIsMapFactory[K](),
4647
NewIsMatchFactory[K](),
4748
NewIsStringFactory[K](),

0 commit comments

Comments
 (0)