Skip to content

Commit def2c0b

Browse files
rockdabootedmocosta
authored andcommitted
[chore] [pkg/ottl] Introduce ctxutil.GetMap() and ctxutil.GetMapKeyName() internal functions (open-telemetry#39952)
#### Description These functions have been requested [here](open-telemetry#39681 (comment)) and [here](open-telemetry#39681 (comment)) as prerequisite for OTTL attributes accessors for the profiles signal. Also adds tests for `GetMap()`, that were missing. #### Testing Unit tests --------- Co-authored-by: Edmo Vamerlatti Costa <[email protected]>
1 parent 8fb2b60 commit def2c0b

File tree

3 files changed

+171
-37
lines changed

3 files changed

+171
-37
lines changed

pkg/ottl/contexts/internal/ctxutil/map.go

Lines changed: 33 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -18,16 +18,9 @@ func GetMapValue[K any](ctx context.Context, tCtx K, m pcommon.Map, keys []ottl.
1818
return nil, errors.New("cannot get map value without keys")
1919
}
2020

21-
s, err := keys[0].String(ctx, tCtx)
21+
s, err := GetMapKeyName(ctx, tCtx, keys[0])
2222
if err != nil {
23-
return nil, err
24-
}
25-
if s == nil {
26-
resString, err := FetchValueFromExpression[K, string](ctx, tCtx, keys[0])
27-
if err != nil {
28-
return nil, fmt.Errorf("unable to resolve a string index in map: %w", err)
29-
}
30-
s = resString
23+
return nil, fmt.Errorf("cannot get map value: %w", err)
3124
}
3225

3326
val, ok := m.Get(*s)
@@ -40,19 +33,12 @@ func GetMapValue[K any](ctx context.Context, tCtx K, m pcommon.Map, keys []ottl.
4033

4134
func SetMapValue[K any](ctx context.Context, tCtx K, m pcommon.Map, keys []ottl.Key[K], val any) error {
4235
if len(keys) == 0 {
43-
return errors.New("cannot set map value without key")
36+
return errors.New("cannot set map value without keys")
4437
}
4538

46-
s, err := keys[0].String(ctx, tCtx)
39+
s, err := GetMapKeyName(ctx, tCtx, keys[0])
4740
if err != nil {
48-
return err
49-
}
50-
if s == nil {
51-
resString, err := FetchValueFromExpression[K, string](ctx, tCtx, keys[0])
52-
if err != nil {
53-
return fmt.Errorf("unable to resolve a string index in map: %w", err)
54-
}
55-
s = resString
41+
return fmt.Errorf("cannot set map value: %w", err)
5642
}
5743

5844
currentValue, ok := m.Get(*s)
@@ -62,6 +48,20 @@ func SetMapValue[K any](ctx context.Context, tCtx K, m pcommon.Map, keys []ottl.
6248
return SetIndexableValue[K](ctx, tCtx, currentValue, val, keys[1:])
6349
}
6450

51+
func GetMapKeyName[K any](ctx context.Context, tCtx K, key ottl.Key[K]) (*string, error) {
52+
resolvedKey, err := key.String(ctx, tCtx)
53+
if err != nil {
54+
return nil, err
55+
}
56+
if resolvedKey == nil {
57+
resolvedKey, err = FetchValueFromExpression[K, string](ctx, tCtx, key)
58+
if err != nil {
59+
return nil, fmt.Errorf("unable to resolve a string index in map: %w", err)
60+
}
61+
}
62+
return resolvedKey, nil
63+
}
64+
6565
func FetchValueFromExpression[K any, T int64 | string](ctx context.Context, tCtx K, key ottl.Key[K]) (*T, error) {
6666
p, err := key.ExpressionGetter(ctx, tCtx)
6767
if err != nil {
@@ -91,3 +91,17 @@ func SetMap(target pcommon.Map, val any) error {
9191
}
9292
return nil
9393
}
94+
95+
func GetMap(val any) (pcommon.Map, error) {
96+
if m, ok := val.(pcommon.Map); ok {
97+
return m, nil
98+
}
99+
if rm, ok := val.(map[string]any); ok {
100+
m := pcommon.NewMap()
101+
if err := m.FromRaw(rm); err != nil {
102+
return pcommon.Map{}, err
103+
}
104+
return m, nil
105+
}
106+
return pcommon.Map{}, fmt.Errorf("failed to convert type %T into pcommon.Map", val)
107+
}

pkg/ottl/contexts/internal/ctxutil/map_test.go

Lines changed: 136 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"testing"
1010

1111
"github.com/stretchr/testify/assert"
12+
"github.com/stretchr/testify/require"
1213
"go.opentelemetry.io/collector/pdata/pcommon"
1314

1415
"github.com/open-telemetry/opentelemetry-collector-contrib/pkg/ottl"
@@ -39,7 +40,7 @@ func Test_GetMapValue_Invalid(t *testing.T) {
3940
G: getSetter,
4041
},
4142
},
42-
err: errors.New("unable to resolve a string index in map: could not resolve key for map/slice, expecting 'string' but got '<nil>'"),
43+
err: errors.New("cannot get map value: unable to resolve a string index in map: could not resolve key for map/slice, expecting 'string' but got '<nil>'"),
4344
},
4445
{
4546
name: "index map with int",
@@ -171,7 +172,7 @@ func Test_SetMapValue_Invalid(t *testing.T) {
171172
G: getSetter,
172173
},
173174
},
174-
err: errors.New("unable to resolve a string index in map: could not resolve key for map/slice, expecting 'string' but got '<nil>'"),
175+
err: errors.New("cannot set map value: unable to resolve a string index in map: could not resolve key for map/slice, expecting 'string' but got '<nil>'"),
175176
},
176177
{
177178
name: "index map with int",
@@ -311,3 +312,136 @@ func Test_SetMapValue_NilKey(t *testing.T) {
311312
err := ctxutil.SetMapValue[any](context.Background(), nil, pcommon.NewMap(), nil, "bar")
312313
assert.Error(t, err)
313314
}
315+
316+
func Test_SetMap(t *testing.T) {
317+
createMap := func() pcommon.Map {
318+
m := pcommon.NewMap()
319+
require.NoError(t, m.FromRaw(map[string]any{"foo": "bar"}))
320+
return m
321+
}
322+
tests := []struct {
323+
name string
324+
val any
325+
err error
326+
expected any
327+
}{
328+
{
329+
name: "invalid type",
330+
val: "invalid",
331+
err: nil, // This is an issue in SetMap(), not returning an error here.
332+
expected: pcommon.NewMap(),
333+
},
334+
{
335+
name: "raw map",
336+
val: map[string]any{"foo": "bar"},
337+
expected: createMap(),
338+
},
339+
{
340+
name: "pcommon.Map",
341+
val: createMap(),
342+
expected: createMap(),
343+
},
344+
}
345+
346+
for _, tt := range tests {
347+
t.Run(tt.name, func(t *testing.T) {
348+
m := pcommon.NewMap()
349+
err := ctxutil.SetMap(m, tt.val)
350+
if tt.err != nil {
351+
require.Equal(t, tt.err, err)
352+
return
353+
}
354+
assert.Equal(t, tt.expected, m)
355+
})
356+
}
357+
}
358+
359+
func Test_GetMap(t *testing.T) {
360+
createMap := func() pcommon.Map {
361+
m := pcommon.NewMap()
362+
require.NoError(t, m.FromRaw(map[string]any{"foo": "bar"}))
363+
return m
364+
}
365+
tests := []struct {
366+
name string
367+
val any
368+
err error
369+
}{
370+
{
371+
name: "invalid type",
372+
val: "invalid",
373+
err: errors.New("failed to convert type string into pcommon.Map"),
374+
},
375+
{
376+
name: "raw map",
377+
val: map[string]any{"foo": "bar"},
378+
},
379+
{
380+
name: "pcommon.Map",
381+
val: createMap(),
382+
},
383+
}
384+
385+
for _, tt := range tests {
386+
t.Run(tt.name, func(t *testing.T) {
387+
m, err := ctxutil.GetMap(tt.val)
388+
if tt.err != nil {
389+
require.Equal(t, tt.err, err)
390+
return
391+
}
392+
assert.Equal(t, m, createMap())
393+
})
394+
}
395+
}
396+
397+
func Test_GetMapKeyName(t *testing.T) {
398+
getSetter := &ottl.StandardGetSetter[any]{
399+
Getter: func(_ context.Context, _ any) (any, error) {
400+
return nil, nil
401+
},
402+
}
403+
tests := []struct {
404+
name string
405+
keys []ottl.Key[any]
406+
err error
407+
key string
408+
}{
409+
{
410+
name: "first key not a string",
411+
keys: []ottl.Key[any]{
412+
&pathtest.Key[any]{
413+
I: ottltest.Intp(0),
414+
G: getSetter,
415+
},
416+
},
417+
err: errors.New("unable to resolve a string index in map: could not resolve key for map/slice, expecting 'string' but got '<nil>'"),
418+
},
419+
{
420+
name: "first key not initialized",
421+
keys: []ottl.Key[any]{
422+
&pathtest.Key[any]{},
423+
},
424+
err: errors.New("unable to resolve a string index in map: invalid key type"),
425+
},
426+
{
427+
name: "valid",
428+
keys: []ottl.Key[any]{
429+
&pathtest.Key[any]{
430+
S: ottltest.Strp("string"),
431+
},
432+
},
433+
key: "string",
434+
},
435+
}
436+
437+
for _, tt := range tests {
438+
t.Run(tt.name, func(t *testing.T) {
439+
resolvedKey, err := ctxutil.GetMapKeyName[any](context.Background(), nil, tt.keys[0])
440+
if tt.err != nil {
441+
assert.Equal(t, tt.err.Error(), err.Error())
442+
return
443+
}
444+
assert.Equal(t, tt.key, *resolvedKey)
445+
})
446+
}
447+
}

pkg/ottl/contexts/internal/ctxutil/value.go

Lines changed: 2 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -74,17 +74,10 @@ func getIndexableValue[K any](ctx context.Context, tCtx K, value pcommon.Value,
7474
for index := 0; index < len(keys); index++ {
7575
switch val.Type() {
7676
case pcommon.ValueTypeMap:
77-
s, err := keys[index].String(ctx, tCtx)
77+
s, err := GetMapKeyName(ctx, tCtx, keys[index])
7878
if err != nil {
7979
return nil, err
8080
}
81-
if s == nil {
82-
resString, err := FetchValueFromExpression[K, string](ctx, tCtx, keys[index])
83-
if err != nil {
84-
return nil, fmt.Errorf("unable to resolve a string index in map: %w", err)
85-
}
86-
s = resString
87-
}
8881
val, ok = val.Map().Get(*s)
8982
if !ok {
9083
return nil, nil
@@ -128,17 +121,10 @@ func SetIndexableValue[K any](ctx context.Context, tCtx K, currentValue pcommon.
128121
for index := 0; index < len(keys); index++ {
129122
switch currentValue.Type() {
130123
case pcommon.ValueTypeMap:
131-
s, err := keys[index].String(ctx, tCtx)
124+
s, err := GetMapKeyName(ctx, tCtx, keys[index])
132125
if err != nil {
133126
return err
134127
}
135-
if s == nil {
136-
resString, err := FetchValueFromExpression[K, string](ctx, tCtx, keys[index])
137-
if err != nil {
138-
return fmt.Errorf("unable to resolve a string index in map: %w", err)
139-
}
140-
s = resString
141-
}
142128
potentialValue, ok := currentValue.Map().Get(*s)
143129
if !ok {
144130
currentValue = currentValue.Map().PutEmpty(*s)

0 commit comments

Comments
 (0)