opentelemetry-collector/pdata/pprofile/json_test.go

308 lines
10 KiB
Go

// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
package pprofile
import (
"testing"
jsoniter "github.com/json-iterator/go"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"go.opentelemetry.io/collector/pdata/pcommon"
)
var (
_ Marshaler = (*JSONMarshaler)(nil)
_ Unmarshaler = (*JSONUnmarshaler)(nil)
)
var profilesOTLP = func() Profiles {
startTimestamp := pcommon.Timestamp(1684617382541971000)
durationTimestamp := pcommon.Timestamp(1684623646539558000)
profileID := ProfileID([16]byte{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10})
traceID := pcommon.TraceID([16]byte{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10})
spanID := pcommon.SpanID([8]byte{0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18})
pd := NewProfiles()
// Add ResourceProfiles.
rp := pd.ResourceProfiles().AppendEmpty()
rp.SetSchemaUrl("schemaURL")
// Add resource.
rp.Resource().Attributes().PutStr("host.name", "testHost")
rp.Resource().Attributes().PutStr("service.name", "testService")
rp.Resource().SetDroppedAttributesCount(1)
// Add ScopeProfiles.
sp := rp.ScopeProfiles().AppendEmpty()
sp.SetSchemaUrl("schemaURL")
sp.Scope().SetName("scope name")
sp.Scope().SetVersion("scope version")
// Add profiles
pro := sp.Profiles().AppendEmpty()
pro.SetProfileID(profileID)
pro.SetTime(startTimestamp)
pro.SetDuration(durationTimestamp)
pro.Attributes().PutStr("hello", "world")
pro.Attributes().PutStr("foo", "bar")
pro.SetDroppedAttributesCount(1)
// Add sample type
st := pro.SampleType().AppendEmpty()
st.SetTypeStrindex(1)
st.SetUnitStrindex(2)
// Add samples
s := pro.Sample().AppendEmpty()
s.SetLocationsStartIndex(1)
s.SetLocationsLength(10)
s.Value().Append(3)
s.AttributeIndices().Append(1)
s.TimestampsUnixNano().Append(12345)
// Add mappings
m := pro.MappingTable().AppendEmpty()
m.SetMemoryStart(2)
m.SetMemoryLimit(3)
m.SetFileOffset(4)
m.SetFilenameStrindex(5)
m.AttributeIndices().Append(7)
m.AttributeIndices().Append(8)
m.SetHasFunctions(true)
m.SetHasFilenames(true)
m.SetHasLineNumbers(true)
m.SetHasInlineFrames(true)
// Add location
l := pro.LocationTable().AppendEmpty()
l.SetMappingIndex(3)
l.SetAddress(4)
l.SetIsFolded(true)
l.AttributeIndices().Append(6)
l.AttributeIndices().Append(7)
li := l.Line().AppendEmpty()
li.SetFunctionIndex(1)
li.SetLine(2)
li.SetColumn(3)
pro.LocationIndices().Append(1)
// Add function
f := pro.FunctionTable().AppendEmpty()
f.SetNameStrindex(2)
f.SetSystemNameStrindex(3)
f.SetFilenameStrindex(4)
f.SetStartLine(5)
// Add attribute table
at := pro.AttributeTable()
a := at.AppendEmpty()
a.SetKey("answer")
a.Value().SetInt(42)
// Add attribute units
au := pro.AttributeUnits().AppendEmpty()
au.SetAttributeKeyStrindex(1)
au.SetUnitStrindex(5)
// Add link table
lt := pro.LinkTable().AppendEmpty()
lt.SetTraceID(traceID)
lt.SetSpanID(spanID)
// Add string table
pro.StringTable().Append("foobar")
pro.SetTime(1234)
pro.SetDuration(5678)
pro.PeriodType().SetTypeStrindex(1)
pro.PeriodType().SetUnitStrindex(2)
pro.SetPeriod(3)
pro.CommentStrindices().Append(1)
pro.CommentStrindices().Append(2)
pro.SetDefaultSampleTypeStrindex(4)
return pd
}()
var profilesJSON = `{"resourceProfiles":[{"resource":{"attributes":[{"key":"host.name","value":{"stringValue":"testHost"}},{"key":"service.name","value":{"stringValue":"testService"}}],"droppedAttributesCount":1},"scopeProfiles":[{"scope":{"name":"scope name","version":"scope version"},"profiles":[{"sampleType":[{"typeStrindex":1,"unitStrindex":2}],"sample":[{"locationsStartIndex":1,"locationsLength":10,"value":["3"],"attributeIndices":[1],"timestampsUnixNano":["12345"]}],"mappingTable":[{"memoryStart":"2","memoryLimit":"3","fileOffset":"4","filenameStrindex":5,"attributeIndices":[7,8],"hasFunctions":true,"hasFilenames":true,"hasLineNumbers":true,"hasInlineFrames":true}],"locationTable":[{"mappingIndex":3,"address":"4","line":[{"functionIndex":1,"line":"2","column":"3"}],"isFolded":true,"attributeIndices":[6,7]}],"locationIndices":[1],"functionTable":[{"nameStrindex":2,"systemNameStrindex":3,"filenameStrindex":4,"startLine":"5"}],"attributeTable":[{"key":"answer","value":{"intValue":"42"}}],"attributeUnits":[{"attributeKeyStrindex":1,"unitStrindex":5}],"linkTable":[{"traceId":"0102030405060708090a0b0c0d0e0f10","spanId":"1112131415161718"}],"stringTable":["foobar"],"timeNanos":"1234","durationNanos":"5678","periodType":{"typeStrindex":1,"unitStrindex":2},"period":"3","commentStrindices":[1,2],"defaultSampleTypeStrindex":4,"profileId":"0102030405060708090a0b0c0d0e0f10","attributes":[{"key":"hello","value":{"stringValue":"world"}},{"key":"foo","value":{"stringValue":"bar"}}],"droppedAttributesCount":1}],"schemaUrl":"schemaURL"}],"schemaUrl":"schemaURL"}]}`
func TestJSONUnmarshal(t *testing.T) {
decoder := &JSONUnmarshaler{}
got, err := decoder.UnmarshalProfiles([]byte(profilesJSON))
require.NoError(t, err)
assert.EqualValues(t, profilesOTLP, got)
}
func TestJSONMarshal(t *testing.T) {
encoder := &JSONMarshaler{}
jsonBuf, err := encoder.MarshalProfiles(profilesOTLP)
require.NoError(t, err)
assert.JSONEq(t, profilesJSON, string(jsonBuf))
}
func TestJSONUnmarshalInvalid(t *testing.T) {
jsonStr := `{"extra":"", "resourceProfiles": "extra"}`
decoder := &JSONUnmarshaler{}
_, err := decoder.UnmarshalProfiles([]byte(jsonStr))
assert.Error(t, err)
}
func TestUnmarshalJsoniterProfileData(t *testing.T) {
jsonStr := `{"extra":"", "resourceProfiles": [{"extra":""}]}`
iter := jsoniter.ConfigFastest.BorrowIterator([]byte(jsonStr))
defer jsoniter.ConfigFastest.ReturnIterator(iter)
val := NewProfiles()
val.unmarshalJsoniter(iter)
require.NoError(t, iter.Error)
assert.Equal(t, 1, val.ResourceProfiles().Len())
}
func TestUnmarshalJsoniterProfileInvalidProfileIDField(t *testing.T) {
jsonStr := `{"profile_id":"--"}`
iter := jsoniter.ConfigFastest.BorrowIterator([]byte(jsonStr))
defer jsoniter.ConfigFastest.ReturnIterator(iter)
NewProfile().unmarshalJsoniter(iter)
assert.ErrorContains(t, iter.Error, "parse profile_id")
}
func TestUnmarshalJsoniterResourceProfiles(t *testing.T) {
jsonStr := `{"extra":"", "resource": {}, "scopeProfiles": []}`
iter := jsoniter.ConfigFastest.BorrowIterator([]byte(jsonStr))
defer jsoniter.ConfigFastest.ReturnIterator(iter)
val := NewResourceProfiles()
val.unmarshalJsoniter(iter)
require.NoError(t, iter.Error)
assert.Equal(t, NewResourceProfiles(), val)
}
func TestUnmarshalJsoniterScopeProfiles(t *testing.T) {
jsonStr := `{"extra":"", "scope": {}, "profiles": []}`
iter := jsoniter.ConfigFastest.BorrowIterator([]byte(jsonStr))
defer jsoniter.ConfigFastest.ReturnIterator(iter)
val := NewScopeProfiles()
val.unmarshalJsoniter(iter)
require.NoError(t, iter.Error)
assert.Equal(t, NewScopeProfiles(), val)
}
func TestUnmarshalJsoniterProfile(t *testing.T) {
jsonStr := `{"extra":""}`
iter := jsoniter.ConfigFastest.BorrowIterator([]byte(jsonStr))
defer jsoniter.ConfigFastest.ReturnIterator(iter)
val := NewProfile()
val.unmarshalJsoniter(iter)
require.NoError(t, iter.Error)
assert.Equal(t, NewProfile(), val)
}
func TestUnmarshalJsoniterValueType(t *testing.T) {
jsonStr := `{"extra":""}`
iter := jsoniter.ConfigFastest.BorrowIterator([]byte(jsonStr))
defer jsoniter.ConfigFastest.ReturnIterator(iter)
val := NewValueType()
val.unmarshalJsoniter(iter)
require.NoError(t, iter.Error)
assert.Equal(t, NewValueType(), val)
}
func TestUnmarshalJsoniterSample(t *testing.T) {
jsonStr := `{"extra":""}`
iter := jsoniter.ConfigFastest.BorrowIterator([]byte(jsonStr))
defer jsoniter.ConfigFastest.ReturnIterator(iter)
val := NewSample()
val.unmarshalJsoniter(iter)
require.NoError(t, iter.Error)
assert.Equal(t, NewSample(), val)
}
func TestUnmarshalJsoniterMapping(t *testing.T) {
jsonStr := `{"extra":""}`
iter := jsoniter.ConfigFastest.BorrowIterator([]byte(jsonStr))
defer jsoniter.ConfigFastest.ReturnIterator(iter)
val := NewMapping()
val.unmarshalJsoniter(iter)
require.NoError(t, iter.Error)
assert.Equal(t, NewMapping(), val)
}
func TestUnmarshalJsoniterLocation(t *testing.T) {
jsonStr := `{"extra":""}`
iter := jsoniter.ConfigFastest.BorrowIterator([]byte(jsonStr))
defer jsoniter.ConfigFastest.ReturnIterator(iter)
val := NewLocation()
val.unmarshalJsoniter(iter)
require.NoError(t, iter.Error)
assert.Equal(t, NewLocation(), val)
}
func TestUnmarshalJsoniterLine(t *testing.T) {
jsonStr := `{"extra":""}`
iter := jsoniter.ConfigFastest.BorrowIterator([]byte(jsonStr))
defer jsoniter.ConfigFastest.ReturnIterator(iter)
val := NewLine()
val.unmarshalJsoniter(iter)
require.NoError(t, iter.Error)
assert.Equal(t, NewLine(), val)
}
func TestUnmarshalJsoniterFunction(t *testing.T) {
jsonStr := `{"extra":""}`
iter := jsoniter.ConfigFastest.BorrowIterator([]byte(jsonStr))
defer jsoniter.ConfigFastest.ReturnIterator(iter)
val := NewFunction()
val.unmarshalJsoniter(iter)
require.NoError(t, iter.Error)
assert.Equal(t, NewFunction(), val)
}
func TestUnmarshalJsoniterAttributeUnit(t *testing.T) {
jsonStr := `{"extra":""}`
iter := jsoniter.ConfigFastest.BorrowIterator([]byte(jsonStr))
defer jsoniter.ConfigFastest.ReturnIterator(iter)
val := NewAttributeUnit()
val.unmarshalJsoniter(iter)
require.NoError(t, iter.Error)
assert.Equal(t, NewAttributeUnit(), val)
}
func TestUnmarshalJsoniterLink(t *testing.T) {
jsonStr := `{"extra":""}`
iter := jsoniter.ConfigFastest.BorrowIterator([]byte(jsonStr))
defer jsoniter.ConfigFastest.ReturnIterator(iter)
val := NewLink()
val.unmarshalJsoniter(iter)
require.NoError(t, iter.Error)
assert.Equal(t, NewLink(), val)
}
func TestUnmarshalJsoniterLinkInvalidTraceIDField(t *testing.T) {
jsonStr := `{"trace_id":"--"}`
iter := jsoniter.ConfigFastest.BorrowIterator([]byte(jsonStr))
defer jsoniter.ConfigFastest.ReturnIterator(iter)
NewLink().unmarshalJsoniter(iter)
assert.ErrorContains(t, iter.Error, "parse trace_id")
}
func TestUnmarshalJsoniterSpanLinkInvalidSpanIDField(t *testing.T) {
jsonStr := `{"span_id":"--"}`
iter := jsoniter.ConfigFastest.BorrowIterator([]byte(jsonStr))
defer jsoniter.ConfigFastest.ReturnIterator(iter)
NewLink().unmarshalJsoniter(iter)
assert.ErrorContains(t, iter.Error, "parse span_id")
}
func BenchmarkJSONUnmarshal(b *testing.B) {
b.ReportAllocs()
encoder := &JSONMarshaler{}
jsonBuf, err := encoder.MarshalProfiles(profilesOTLP)
require.NoError(b, err)
decoder := &JSONUnmarshaler{}
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
_, err := decoder.UnmarshalProfiles(jsonBuf)
assert.NoError(b, err)
}
})
}