1// Copyright The OpenTelemetry Authors
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package transform
16
17import (
18	"testing"
19
20	"github.com/stretchr/testify/assert"
21
22	commonpb "go.opentelemetry.io/otel/exporters/otlp/internal/opentelemetry-proto-gen/common/v1"
23	"go.opentelemetry.io/otel/label"
24)
25
26type attributeTest struct {
27	attrs    []label.KeyValue
28	expected []*commonpb.KeyValue
29}
30
31func TestAttributes(t *testing.T) {
32	for _, test := range []attributeTest{
33		{nil, nil},
34		{
35			[]label.KeyValue{
36				label.Int("int to int", 123),
37				label.Uint("uint to int", 1234),
38				label.Int32("int32 to int", 12345),
39				label.Uint32("uint32 to int", 123456),
40				label.Int64("int64 to int64", 1234567),
41				label.Uint64("uint64 to int64", 12345678),
42				label.Float32("float32 to double", 3.14),
43				label.Float32("float64 to double", 1.61),
44				label.String("string to string", "string"),
45				label.Bool("bool to bool", true),
46			},
47			[]*commonpb.KeyValue{
48				{
49					Key: "int to int",
50					Value: &commonpb.AnyValue{
51						Value: &commonpb.AnyValue_IntValue{
52							IntValue: 123,
53						},
54					},
55				},
56				{
57					Key: "uint to int",
58					Value: &commonpb.AnyValue{
59						Value: &commonpb.AnyValue_IntValue{
60							IntValue: 1234,
61						},
62					},
63				},
64				{
65					Key: "int32 to int",
66					Value: &commonpb.AnyValue{
67						Value: &commonpb.AnyValue_IntValue{
68							IntValue: 12345,
69						},
70					},
71				},
72				{
73					Key: "uint32 to int",
74					Value: &commonpb.AnyValue{
75						Value: &commonpb.AnyValue_IntValue{
76							IntValue: 123456,
77						},
78					},
79				},
80				{
81					Key: "int64 to int64",
82					Value: &commonpb.AnyValue{
83						Value: &commonpb.AnyValue_IntValue{
84							IntValue: 1234567,
85						},
86					},
87				},
88				{
89					Key: "uint64 to int64",
90					Value: &commonpb.AnyValue{
91						Value: &commonpb.AnyValue_IntValue{
92							IntValue: 12345678,
93						},
94					},
95				},
96				{
97					Key: "float32 to double",
98					Value: &commonpb.AnyValue{
99						Value: &commonpb.AnyValue_DoubleValue{
100							DoubleValue: 3.14,
101						},
102					},
103				},
104				{
105					Key: "float64 to double",
106					Value: &commonpb.AnyValue{
107						Value: &commonpb.AnyValue_DoubleValue{
108							DoubleValue: 1.61,
109						},
110					},
111				},
112				{
113					Key: "string to string",
114					Value: &commonpb.AnyValue{
115						Value: &commonpb.AnyValue_StringValue{
116							StringValue: "string",
117						},
118					},
119				},
120				{
121					Key: "bool to bool",
122					Value: &commonpb.AnyValue{
123						Value: &commonpb.AnyValue_BoolValue{
124							BoolValue: true,
125						},
126					},
127				},
128			},
129		},
130	} {
131		got := Attributes(test.attrs)
132		if !assert.Len(t, got, len(test.expected)) {
133			continue
134		}
135		for i, actual := range got {
136			if a, ok := actual.Value.Value.(*commonpb.AnyValue_DoubleValue); ok {
137				e, ok := test.expected[i].Value.Value.(*commonpb.AnyValue_DoubleValue)
138				if !ok {
139					t.Errorf("expected AnyValue_DoubleValue, got %T", test.expected[i].Value.Value)
140					continue
141				}
142				if !assert.InDelta(t, e.DoubleValue, a.DoubleValue, 0.01) {
143					continue
144				}
145				e.DoubleValue = a.DoubleValue
146			}
147			assert.Equal(t, test.expected[i], actual)
148		}
149	}
150}
151
152func TestArrayAttributes(t *testing.T) {
153	// Array KeyValue supports only arrays of primitive types:
154	// "bool", "int", "int32", "int64",
155	// "float32", "float64", "string",
156	// "uint", "uint32", "uint64"
157	for _, test := range []attributeTest{
158		{nil, nil},
159		{
160			[]label.KeyValue{
161				label.Array("invalid", [][]string{{"1", "2"}, {"a"}}),
162			},
163			[]*commonpb.KeyValue{
164				{
165					Key: "invalid",
166					Value: &commonpb.AnyValue{
167						Value: &commonpb.AnyValue_StringValue{
168							StringValue: "INVALID",
169						},
170					},
171				},
172			},
173		},
174		{
175			[]label.KeyValue{
176				label.Array("bool array to bool array", []bool{true, false}),
177				label.Array("int array to int64 array", []int{1, 2, 3}),
178				label.Array("uint array to int64 array", []uint{1, 2, 3}),
179				label.Array("int32 array to int64 array", []int32{1, 2, 3}),
180				label.Array("uint32 array to int64 array", []uint32{1, 2, 3}),
181				label.Array("int64 array to int64 array", []int64{1, 2, 3}),
182				label.Array("uint64 array to int64 array", []uint64{1, 2, 3}),
183				label.Array("float32 array to double array", []float32{1.11, 2.22, 3.33}),
184				label.Array("float64 array to double array", []float64{1.11, 2.22, 3.33}),
185				label.Array("string array to string array", []string{"foo", "bar", "baz"}),
186			},
187			[]*commonpb.KeyValue{
188				newOTelBoolArray("bool array to bool array", []bool{true, false}),
189				newOTelIntArray("int array to int64 array", []int64{1, 2, 3}),
190				newOTelIntArray("uint array to int64 array", []int64{1, 2, 3}),
191				newOTelIntArray("int32 array to int64 array", []int64{1, 2, 3}),
192				newOTelIntArray("uint32 array to int64 array", []int64{1, 2, 3}),
193				newOTelIntArray("int64 array to int64 array", []int64{1, 2, 3}),
194				newOTelIntArray("uint64 array to int64 array", []int64{1, 2, 3}),
195				newOTelDoubleArray("float32 array to double array", []float64{1.11, 2.22, 3.33}),
196				newOTelDoubleArray("float64 array to double array", []float64{1.11, 2.22, 3.33}),
197				newOTelStringArray("string array to string array", []string{"foo", "bar", "baz"}),
198			},
199		},
200	} {
201		actualArrayAttributes := Attributes(test.attrs)
202		expectedArrayAttributes := test.expected
203		if !assert.Len(t, actualArrayAttributes, len(expectedArrayAttributes)) {
204			continue
205		}
206
207		for i, actualArrayAttr := range actualArrayAttributes {
208			expectedArrayAttr := expectedArrayAttributes[i]
209			expectedKey, actualKey := expectedArrayAttr.Key, actualArrayAttr.Key
210			if !assert.Equal(t, expectedKey, actualKey) {
211				continue
212			}
213
214			expected := expectedArrayAttr.Value.GetArrayValue()
215			actual := actualArrayAttr.Value.GetArrayValue()
216			if expected == nil {
217				assert.Nil(t, actual)
218				continue
219			}
220			if assert.NotNil(t, actual, "expected not nil for %s", actualKey) {
221				assertExpectedArrayValues(t, expected.Values, actual.Values)
222			}
223		}
224
225	}
226}
227
228func assertExpectedArrayValues(t *testing.T, expectedValues, actualValues []*commonpb.AnyValue) {
229	for i, actual := range actualValues {
230		expected := expectedValues[i]
231		if a, ok := actual.Value.(*commonpb.AnyValue_DoubleValue); ok {
232			e, ok := expected.Value.(*commonpb.AnyValue_DoubleValue)
233			if !ok {
234				t.Errorf("expected AnyValue_DoubleValue, got %T", expected.Value)
235				continue
236			}
237			if !assert.InDelta(t, e.DoubleValue, a.DoubleValue, 0.01) {
238				continue
239			}
240			e.DoubleValue = a.DoubleValue
241		}
242		assert.Equal(t, expected, actual)
243	}
244}
245
246func newOTelBoolArray(key string, values []bool) *commonpb.KeyValue {
247	arrayValues := []*commonpb.AnyValue{}
248	for _, b := range values {
249		arrayValues = append(arrayValues, &commonpb.AnyValue{
250			Value: &commonpb.AnyValue_BoolValue{
251				BoolValue: b,
252			},
253		})
254	}
255
256	return newOTelArray(key, arrayValues)
257}
258
259func newOTelIntArray(key string, values []int64) *commonpb.KeyValue {
260	arrayValues := []*commonpb.AnyValue{}
261
262	for _, i := range values {
263		arrayValues = append(arrayValues, &commonpb.AnyValue{
264			Value: &commonpb.AnyValue_IntValue{
265				IntValue: i,
266			},
267		})
268	}
269
270	return newOTelArray(key, arrayValues)
271}
272
273func newOTelDoubleArray(key string, values []float64) *commonpb.KeyValue {
274	arrayValues := []*commonpb.AnyValue{}
275
276	for _, d := range values {
277		arrayValues = append(arrayValues, &commonpb.AnyValue{
278			Value: &commonpb.AnyValue_DoubleValue{
279				DoubleValue: d,
280			},
281		})
282	}
283
284	return newOTelArray(key, arrayValues)
285}
286
287func newOTelStringArray(key string, values []string) *commonpb.KeyValue {
288	arrayValues := []*commonpb.AnyValue{}
289
290	for _, s := range values {
291		arrayValues = append(arrayValues, &commonpb.AnyValue{
292			Value: &commonpb.AnyValue_StringValue{
293				StringValue: s,
294			},
295		})
296	}
297
298	return newOTelArray(key, arrayValues)
299}
300
301func newOTelArray(key string, arrayValues []*commonpb.AnyValue) *commonpb.KeyValue {
302	return &commonpb.KeyValue{
303		Key: key,
304		Value: &commonpb.AnyValue{
305			Value: &commonpb.AnyValue_ArrayValue{
306				ArrayValue: &commonpb.ArrayValue{
307					Values: arrayValues,
308				},
309			},
310		},
311	}
312}
313