opentelemetry-collector/pdata/pprofile/attributes_test.go

245 lines
7.0 KiB
Go

// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
package pprofile
import (
"fmt"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"go.opentelemetry.io/collector/pdata/pcommon"
)
func TestAddAttribute(t *testing.T) {
table := NewAttributeTableSlice()
att := table.AppendEmpty()
att.SetKey("hello")
att.Value().SetStr("world")
// Add a brand new attribute
loc := NewLocation()
err := AddAttribute(table, loc, "bonjour", pcommon.NewValueStr("monde"))
require.NoError(t, err)
assert.Equal(t, 2, table.Len())
assert.Equal(t, []int32{1}, loc.AttributeIndices().AsRaw())
// Add an already existing attribute
mapp := NewMapping()
err = AddAttribute(table, mapp, "hello", pcommon.NewValueStr("world"))
require.NoError(t, err)
assert.Equal(t, 2, table.Len())
assert.Equal(t, []int32{0}, mapp.AttributeIndices().AsRaw())
// Add a duplicate attribute
err = AddAttribute(table, mapp, "hello", pcommon.NewValueStr("world"))
require.NoError(t, err)
assert.Equal(t, 2, table.Len())
assert.Equal(t, []int32{0}, mapp.AttributeIndices().AsRaw())
}
func TestFromAttributeIndices(t *testing.T) {
table := NewAttributeTableSlice()
att := table.AppendEmpty()
att.SetKey("hello")
att.Value().SetStr("world")
att2 := table.AppendEmpty()
att2.SetKey("bonjour")
att2.Value().SetStr("monde")
attrs := FromAttributeIndices(table, NewProfile())
assert.Equal(t, attrs, pcommon.NewMap())
// A Location with a single attribute
loc := NewLocation()
loc.AttributeIndices().Append(0)
attrs = FromAttributeIndices(table, loc)
m := map[string]any{"hello": "world"}
assert.Equal(t, attrs.AsRaw(), m)
// A Mapping with two attributes
mapp := NewLocation()
mapp.AttributeIndices().Append(0, 1)
attrs = FromAttributeIndices(table, mapp)
m = map[string]any{"hello": "world", "bonjour": "monde"}
assert.Equal(t, attrs.AsRaw(), m)
}
func testPutAttribute(t *testing.T, record attributable) {
table := NewAttributeTableSlice()
// Put a first attribute.
require.NoError(t, PutAttribute(table, record, "hello", pcommon.NewValueStr("world")))
assert.Equal(t, 1, table.Len())
assert.Equal(t, []int32{0}, record.AttributeIndices().AsRaw())
// Put an attribute, same key, same value.
// This should be a no-op.
require.NoError(t, PutAttribute(table, record, "hello", pcommon.NewValueStr("world")))
assert.Equal(t, 1, table.Len())
assert.Equal(t, []int32{0}, record.AttributeIndices().AsRaw())
// Special case: removing and adding again should not change the table as
// this can lead to multiple identical attributes in the table.
record.AttributeIndices().FromRaw([]int32{})
require.NoError(t, PutAttribute(table, record, "hello", pcommon.NewValueStr("world")))
assert.Equal(t, 1, table.Len())
assert.Equal(t, []int32{0}, record.AttributeIndices().AsRaw())
// Put an attribute, same key, different value.
// This updates the index and adds to the table.
require.NoError(t, PutAttribute(table, record, "hello", pcommon.NewValueStr("world2")))
assert.Equal(t, 2, table.Len())
assert.Equal(t, []int32{1}, record.AttributeIndices().AsRaw())
// Put an attribute that already exists in the table.
// This updates the index and does not add to the table.
require.NoError(t, PutAttribute(table, record, "hello", pcommon.NewValueStr("world")))
assert.Equal(t, 2, table.Len())
assert.Equal(t, []int32{0}, record.AttributeIndices().AsRaw())
// Put a new attribute.
// This adds an index and adds to the table.
require.NoError(t, PutAttribute(table, record, "good", pcommon.NewValueStr("day")))
assert.Equal(t, 3, table.Len())
assert.Equal(t, []int32{0, 2}, record.AttributeIndices().AsRaw())
// Add multiple distinct attributes.
for i := range 100 {
require.NoError(t, PutAttribute(table, record, fmt.Sprintf("key_%d", i), pcommon.NewValueStr("day")))
assert.Equal(t, i+4, table.Len())
assert.Equal(t, i+3, record.AttributeIndices().Len())
}
// Add a negative index to the record.
record.AttributeIndices().Append(-1)
tableLen := table.Len()
indicesLen := record.AttributeIndices().Len()
// Try putting a new attribute, make sure it fails, and that table/indices didn't change.
require.Error(t, PutAttribute(table, record, "newKey", pcommon.NewValueStr("value")))
require.Equal(t, tableLen, table.Len())
require.Equal(t, indicesLen, record.AttributeIndices().Len())
// Set the last index to the table length, which is out of range.
record.AttributeIndices().SetAt(indicesLen-1, int32(tableLen)) //nolint:gosec
// Try putting a new attribute, make sure it fails, and that table/indices didn't change.
require.Error(t, PutAttribute(table, record, "newKey", pcommon.NewValueStr("value")))
require.Equal(t, tableLen, table.Len())
require.Equal(t, indicesLen, record.AttributeIndices().Len())
}
func TestPutAttribute(t *testing.T) {
// Test every existing record type.
for _, tt := range []struct {
name string
attr attributable
}{
{"Profile", NewProfile()},
{"Sample", NewSample()},
{"Mapping", NewMapping()},
{"Location", NewLocation()},
} {
t.Run(tt.name, func(t *testing.T) {
testPutAttribute(t, tt.attr)
})
}
}
func BenchmarkFromAttributeIndices(b *testing.B) {
table := NewAttributeTableSlice()
for i := range 10 {
att := table.AppendEmpty()
att.SetKey(fmt.Sprintf("key_%d", i))
att.Value().SetStr(fmt.Sprintf("value_%d", i))
}
obj := NewLocation()
obj.AttributeIndices().Append(1, 3, 7)
b.ResetTimer()
b.ReportAllocs()
for n := 0; n < b.N; n++ {
_ = FromAttributeIndices(table, obj)
}
}
func BenchmarkPutAttribute(b *testing.B) {
for _, bb := range []struct {
name string
key string
value pcommon.Value
runBefore func(*testing.B, AttributeTableSlice, attributable)
}{
{
name: "with a new string attribute",
key: "attribute",
value: pcommon.NewValueStr("test"),
},
{
name: "with an existing attribute",
key: "attribute",
value: pcommon.NewValueStr("test"),
runBefore: func(_ *testing.B, table AttributeTableSlice, _ attributable) {
entry := table.AppendEmpty()
entry.SetKey("attribute")
entry.Value().SetStr("test")
},
},
{
name: "with a duplicate attribute",
key: "attribute",
value: pcommon.NewValueStr("test"),
runBefore: func(_ *testing.B, table AttributeTableSlice, obj attributable) {
require.NoError(b, PutAttribute(table, obj, "attribute", pcommon.NewValueStr("test")))
},
},
{
name: "with a hundred attributes to loop through",
key: "attribute",
value: pcommon.NewValueStr("test"),
runBefore: func(_ *testing.B, table AttributeTableSlice, _ attributable) {
for i := range 100 {
entry := table.AppendEmpty()
entry.SetKey(fmt.Sprintf("attr_%d", i))
entry.Value().SetStr("test")
}
entry := table.AppendEmpty()
entry.SetKey("attribute")
entry.Value().SetStr("test")
},
},
} {
b.Run(bb.name, func(b *testing.B) {
table := NewAttributeTableSlice()
obj := NewLocation()
if bb.runBefore != nil {
bb.runBefore(b, table, obj)
}
b.ResetTimer()
b.ReportAllocs()
for n := 0; n < b.N; n++ {
_ = PutAttribute(table, obj, bb.key, bb.value)
}
})
}
}