245 lines
7.0 KiB
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)
|
|
}
|
|
})
|
|
}
|
|
}
|