Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
aos
GitHub Repository: aos/grafana-agent
Path: blob/main/pkg/river/internal/value/value_test.go
4096 views
1
package value_test
2
3
import (
4
"fmt"
5
"io"
6
"testing"
7
8
"github.com/grafana/agent/pkg/river/internal/value"
9
"github.com/stretchr/testify/require"
10
)
11
12
// TestEncodeKeyLookup tests where Go values are retained correctly
13
// throughout values with a key lookup.
14
func TestEncodeKeyLookup(t *testing.T) {
15
type Body struct {
16
Data pointerMarshaler `river:"data,attr"`
17
}
18
19
tt := []struct {
20
name string
21
encodeTarget any
22
key string
23
24
expectBodyType value.Type
25
expectKeyExists bool
26
expectKeyValue value.Value
27
expectKeyType value.Type
28
}{
29
{
30
name: "Struct Encode data Key",
31
encodeTarget: &Body{},
32
key: "data",
33
expectBodyType: value.TypeObject,
34
expectKeyExists: true,
35
expectKeyValue: value.String("Hello, world!"),
36
expectKeyType: value.TypeString,
37
},
38
{
39
name: "Struct Encode Missing Key",
40
encodeTarget: &Body{},
41
key: "missing",
42
expectBodyType: value.TypeObject,
43
expectKeyExists: false,
44
expectKeyValue: value.Null,
45
expectKeyType: value.TypeNull,
46
},
47
{
48
name: "Map Encode data Key",
49
encodeTarget: map[string]string{"data": "Hello, world!"},
50
key: "data",
51
expectBodyType: value.TypeObject,
52
expectKeyExists: true,
53
expectKeyValue: value.String("Hello, world!"),
54
expectKeyType: value.TypeString,
55
},
56
{
57
name: "Map Encode Missing Key",
58
encodeTarget: map[string]string{"data": "Hello, world!"},
59
key: "missing",
60
expectBodyType: value.TypeObject,
61
expectKeyExists: false,
62
expectKeyValue: value.Null,
63
expectKeyType: value.TypeNull,
64
},
65
{
66
name: "Map Encode empty value Key",
67
encodeTarget: map[string]string{"data": ""},
68
key: "data",
69
expectBodyType: value.TypeObject,
70
expectKeyExists: true,
71
expectKeyValue: value.String(""),
72
expectKeyType: value.TypeString,
73
},
74
}
75
76
for _, tc := range tt {
77
t.Run(tc.name, func(t *testing.T) {
78
bodyVal := value.Encode(tc.encodeTarget)
79
require.Equal(t, tc.expectBodyType, bodyVal.Type())
80
81
val, ok := bodyVal.Key(tc.key)
82
require.Equal(t, tc.expectKeyExists, ok)
83
require.Equal(t, tc.expectKeyType, val.Type())
84
switch val.Type() {
85
case value.TypeString:
86
require.Equal(t, tc.expectKeyValue.Text(), val.Text())
87
case value.TypeNull:
88
require.Equal(t, tc.expectKeyValue, val)
89
default:
90
require.Fail(t, "unexpected value type (this switch can be expanded)")
91
}
92
})
93
}
94
}
95
96
// TestEncodeNoKeyLookup tests where Go values are retained correctly
97
// throughout values without a key lookup.
98
func TestEncodeNoKeyLookup(t *testing.T) {
99
tt := []struct {
100
name string
101
encodeTarget any
102
key string
103
104
expectBodyType value.Type
105
expectBodyText string
106
}{
107
{
108
name: "Encode",
109
encodeTarget: &pointerMarshaler{},
110
expectBodyType: value.TypeString,
111
expectBodyText: "Hello, world!",
112
},
113
}
114
115
for _, tc := range tt {
116
t.Run(tc.name, func(t *testing.T) {
117
bodyVal := value.Encode(tc.encodeTarget)
118
require.Equal(t, tc.expectBodyType, bodyVal.Type())
119
require.Equal(t, "Hello, world!", bodyVal.Text())
120
})
121
}
122
}
123
124
type pointerMarshaler struct{}
125
126
func (*pointerMarshaler) MarshalText() ([]byte, error) {
127
return []byte("Hello, world!"), nil
128
}
129
130
func TestValue_Call(t *testing.T) {
131
t.Run("simple", func(t *testing.T) {
132
add := func(a, b int) int { return a + b }
133
addVal := value.Encode(add)
134
135
res, err := addVal.Call(
136
value.Int(15),
137
value.Int(43),
138
)
139
require.NoError(t, err)
140
require.Equal(t, int64(15+43), res.Int())
141
})
142
143
t.Run("fully variadic", func(t *testing.T) {
144
add := func(nums ...int) int {
145
var sum int
146
for _, num := range nums {
147
sum += num
148
}
149
return sum
150
}
151
addVal := value.Encode(add)
152
153
t.Run("no args", func(t *testing.T) {
154
res, err := addVal.Call()
155
require.NoError(t, err)
156
require.Equal(t, int64(0), res.Int())
157
})
158
159
t.Run("one arg", func(t *testing.T) {
160
res, err := addVal.Call(value.Int(32))
161
require.NoError(t, err)
162
require.Equal(t, int64(32), res.Int())
163
})
164
165
t.Run("many args", func(t *testing.T) {
166
res, err := addVal.Call(
167
value.Int(32),
168
value.Int(59),
169
value.Int(12),
170
)
171
require.NoError(t, err)
172
require.Equal(t, int64(32+59+12), res.Int())
173
})
174
})
175
176
t.Run("partially variadic", func(t *testing.T) {
177
add := func(firstNum int, nums ...int) int {
178
sum := firstNum
179
for _, num := range nums {
180
sum += num
181
}
182
return sum
183
}
184
addVal := value.Encode(add)
185
186
t.Run("no variadic args", func(t *testing.T) {
187
res, err := addVal.Call(value.Int(52))
188
require.NoError(t, err)
189
require.Equal(t, int64(52), res.Int())
190
})
191
192
t.Run("one variadic arg", func(t *testing.T) {
193
res, err := addVal.Call(value.Int(52), value.Int(32))
194
require.NoError(t, err)
195
require.Equal(t, int64(52+32), res.Int())
196
})
197
198
t.Run("many variadic args", func(t *testing.T) {
199
res, err := addVal.Call(
200
value.Int(32),
201
value.Int(59),
202
value.Int(12),
203
)
204
require.NoError(t, err)
205
require.Equal(t, int64(32+59+12), res.Int())
206
})
207
})
208
209
t.Run("returns error", func(t *testing.T) {
210
failWhenTrue := func(val bool) (int, error) {
211
if val {
212
return 0, fmt.Errorf("function failed for a very good reason")
213
}
214
return 0, nil
215
}
216
funcVal := value.Encode(failWhenTrue)
217
218
t.Run("no error", func(t *testing.T) {
219
res, err := funcVal.Call(value.Bool(false))
220
require.NoError(t, err)
221
require.Equal(t, int64(0), res.Int())
222
})
223
224
t.Run("error", func(t *testing.T) {
225
_, err := funcVal.Call(value.Bool(true))
226
require.EqualError(t, err, "function failed for a very good reason")
227
})
228
})
229
}
230
231
func TestValue_Interface_In_Array(t *testing.T) {
232
type Container struct {
233
Field io.Closer `river:"field,attr"`
234
}
235
236
val := value.Encode(Container{Field: io.NopCloser(nil)})
237
fieldVal, ok := val.Key("field")
238
require.True(t, ok, "field not found in object")
239
require.Equal(t, value.TypeCapsule, fieldVal.Type())
240
241
arrVal := value.Array(fieldVal)
242
require.Equal(t, value.TypeCapsule, arrVal.Index(0).Type())
243
}
244
245