pkg/pdatatest/pprofiletest/profiles.go (723 lines of code) (raw):
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
package pprofiletest // import "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/pdatatest/pprofiletest"
import (
"bytes"
"fmt"
"reflect"
"go.opentelemetry.io/collector/pdata/pprofile"
"go.uber.org/multierr"
"github.com/open-telemetry/opentelemetry-collector-contrib/pkg/pdatatest/internal"
)
// CompareProfiles compares each part of two given Profiles and returns
// an error if they don't match. The error describes what didn't match.
func CompareProfiles(expected, actual pprofile.Profiles, options ...CompareProfilesOption) error {
exp, act := pprofile.NewProfiles(), pprofile.NewProfiles()
expected.CopyTo(exp)
actual.CopyTo(act)
for _, option := range options {
option.applyOnProfiles(exp, act)
}
if exp.IsReadOnly() != act.IsReadOnly() {
return fmt.Errorf("readOnly state differs from expected '%t'", exp.IsReadOnly())
}
if exp.SampleCount() != act.SampleCount() {
return fmt.Errorf("sample count state differs from expected '%d', actual '%d'", exp.SampleCount(), act.SampleCount())
}
expectedProfiles, actualProfiles := exp.ResourceProfiles(), act.ResourceProfiles()
if expectedProfiles.Len() != actualProfiles.Len() {
return fmt.Errorf("number of resources doesn't match expected: %d, actual: %d",
expectedProfiles.Len(), actualProfiles.Len())
}
numResources := expectedProfiles.Len()
// Keep track of matching resources so that each can only be matched once
matchingResources := make(map[pprofile.ResourceProfiles]pprofile.ResourceProfiles, numResources)
var errs error
var outOfOrderErrs error
for e := 0; e < numResources; e++ {
er := expectedProfiles.At(e)
var foundMatch bool
for a := 0; a < numResources; a++ {
ar := actualProfiles.At(a)
if _, ok := matchingResources[ar]; ok {
continue
}
if reflect.DeepEqual(er.Resource().Attributes().AsRaw(), ar.Resource().Attributes().AsRaw()) {
foundMatch = true
matchingResources[ar] = er
if e != a {
outOfOrderErrs = multierr.Append(outOfOrderErrs,
fmt.Errorf(`resources are out of order: resource "%v" expected at index %d, found at index %d`,
er.Resource().Attributes().AsRaw(), e, a))
}
break
}
}
if !foundMatch {
errs = multierr.Append(errs, fmt.Errorf("missing expected resource: %v", er.Resource().Attributes().AsRaw()))
}
}
for i := 0; i < numResources; i++ {
if _, ok := matchingResources[actualProfiles.At(i)]; !ok {
errs = multierr.Append(errs, fmt.Errorf("unexpected resource: %v", actualProfiles.At(i).Resource().Attributes().AsRaw()))
}
}
if errs != nil {
return errs
}
if outOfOrderErrs != nil {
return outOfOrderErrs
}
for ar, er := range matchingResources {
errPrefix := fmt.Sprintf(`resource "%v"`, er.Resource().Attributes().AsRaw())
errs = multierr.Append(errs, internal.AddErrPrefix(errPrefix, CompareResourceProfiles(er, ar)))
}
return errs
}
// CompareResourceProfiles compares each part of two given ResourceProfiles and returns
// an error if they don't match. The error describes what didn't match.
func CompareResourceProfiles(expected, actual pprofile.ResourceProfiles) error {
errs := multierr.Combine(
internal.CompareResource(expected.Resource(), actual.Resource()),
internal.CompareSchemaURL(expected.SchemaUrl(), actual.SchemaUrl()),
)
esls := expected.ScopeProfiles()
asls := actual.ScopeProfiles()
if esls.Len() != asls.Len() {
errs = multierr.Append(errs, fmt.Errorf("number of scopes doesn't match expected: %d, actual: %d", esls.Len(),
asls.Len()))
return errs
}
numScopeProfiles := esls.Len()
// Keep track of matching scope profiles so that each container can only be matched once
matchingScopeProfiles := make(map[pprofile.ScopeProfiles]pprofile.ScopeProfiles, numScopeProfiles)
var outOfOrderErrs error
for e := 0; e < numScopeProfiles; e++ {
esl := expected.ScopeProfiles().At(e)
var foundMatch bool
for a := 0; a < numScopeProfiles; a++ {
asl := actual.ScopeProfiles().At(a)
if _, ok := matchingScopeProfiles[asl]; ok {
continue
}
if esl.Scope().Name() == asl.Scope().Name() {
foundMatch = true
matchingScopeProfiles[asl] = esl
if e != a {
outOfOrderErrs = multierr.Append(outOfOrderErrs,
fmt.Errorf("scopes are out of order: scope %s expected at index %d, found at index %d",
esl.Scope().Name(), e, a))
}
break
}
}
if !foundMatch {
errs = multierr.Append(errs, fmt.Errorf("missing expected scope: %s", esl.Scope().Name()))
}
}
for i := 0; i < numScopeProfiles; i++ {
if _, ok := matchingScopeProfiles[actual.ScopeProfiles().At(i)]; !ok {
errs = multierr.Append(errs, fmt.Errorf("unexpected scope: %s", actual.ScopeProfiles().At(i).Scope().Name()))
}
}
if errs != nil {
return errs
}
if outOfOrderErrs != nil {
return outOfOrderErrs
}
for i := 0; i < esls.Len(); i++ {
errPrefix := fmt.Sprintf(`scope "%s"`, esls.At(i).Scope().Name())
errs = multierr.Append(errs, internal.AddErrPrefix(errPrefix, CompareScopeProfiles(esls.At(i), asls.At(i))))
}
return errs
}
// CompareScopeProfiles compares each part of two given ProfilesSlices and returns
// an error if they don't match. The error describes what didn't match.
func CompareScopeProfiles(expected, actual pprofile.ScopeProfiles) error {
errs := multierr.Combine(
internal.CompareInstrumentationScope(expected.Scope(), actual.Scope()),
internal.CompareSchemaURL(expected.SchemaUrl(), actual.SchemaUrl()),
)
if expected.Profiles().Len() != actual.Profiles().Len() {
errs = multierr.Append(errs, fmt.Errorf("number of profiles doesn't match expected: %d, actual: %d",
expected.Profiles().Len(), actual.Profiles().Len()))
return errs
}
numProfiles := expected.Profiles().Len()
// Keep track of matching containers so that each container can only be matched once
matchingProfiles := make(map[pprofile.Profile]pprofile.Profile, numProfiles)
var outOfOrderErrs error
for e := 0; e < numProfiles; e++ {
elr := expected.Profiles().At(e)
errs = multierr.Append(errs, ValidateProfile(elr))
em := profileAttributesToMap(elr)
var foundMatch bool
for a := 0; a < numProfiles; a++ {
alr := actual.Profiles().At(a)
errs = multierr.Append(errs, ValidateProfile(alr))
if _, ok := matchingProfiles[alr]; ok {
continue
}
am := profileAttributesToMap(alr)
if reflect.DeepEqual(em, am) {
foundMatch = true
matchingProfiles[alr] = elr
if e != a {
outOfOrderErrs = multierr.Append(outOfOrderErrs,
fmt.Errorf(`profiles are out of order: profile "%v" expected at index %d, found at index %d`,
em, e, a))
}
break
}
}
if !foundMatch {
errs = multierr.Append(errs, fmt.Errorf("missing expected profile: %v", em))
}
}
for i := 0; i < numProfiles; i++ {
if _, ok := matchingProfiles[actual.Profiles().At(i)]; !ok {
errs = multierr.Append(errs, fmt.Errorf("unexpected profile: %v",
profileAttributesToMap(actual.Profiles().At(i))))
}
}
if errs != nil {
return errs
}
if outOfOrderErrs != nil {
return outOfOrderErrs
}
for alr, elr := range matchingProfiles {
errPrefix := fmt.Sprintf(`profile "%v"`, profileAttributesToMap(elr))
errs = multierr.Append(errs, internal.AddErrPrefix(errPrefix, CompareProfile(elr, alr)))
}
return errs
}
func compareAttributes(a, b pprofile.Profile) error {
aa := profileAttributesToMap(a)
ba := profileAttributesToMap(b)
if !reflect.DeepEqual(aa, ba) {
return fmt.Errorf("attributes don't match expected: %v, actual: %v", aa, ba)
}
return nil
}
func CompareProfile(expected, actual pprofile.Profile) error {
errs := multierr.Combine(
compareAttributes(expected, actual),
internal.CompareDroppedAttributesCount(expected.DroppedAttributesCount(), actual.DroppedAttributesCount()),
)
if expected.ProfileID().String() != actual.ProfileID().String() {
errs = multierr.Append(errs, fmt.Errorf("profileID does not match expected '%s', actual '%s'", expected.ProfileID().String(), actual.ProfileID().String()))
}
if expected.StartTime() != actual.StartTime() {
errs = multierr.Append(errs, fmt.Errorf("start timestamp doesn't match expected: %d, "+"actual: %d", expected.StartTime(), actual.StartTime()))
}
if !reflect.DeepEqual(expected.LocationIndices(), actual.LocationIndices()) {
errs = multierr.Append(errs, fmt.Errorf("locationIndicies do not match expected"))
}
if !reflect.DeepEqual(expected.CommentStrindices(), actual.CommentStrindices()) {
errs = multierr.Append(errs, fmt.Errorf("comment does not match expected"))
}
if expected.Time() != actual.Time() {
errs = multierr.Append(errs, fmt.Errorf("time doesn't match expected: %d, actual: %d", expected.Time(), actual.Time()))
}
if !reflect.DeepEqual(expected.StringTable(), actual.StringTable()) {
errs = multierr.Append(errs, fmt.Errorf("stringTable '%v' does not match expected '%v'", actual.StringTable().AsRaw(), expected.StringTable().AsRaw()))
}
if expected.OriginalPayloadFormat() != actual.OriginalPayloadFormat() {
errs = multierr.Append(errs, fmt.Errorf("originalPayloadFormat does not match expected '%s', actual '%s'", expected.OriginalPayloadFormat(), actual.OriginalPayloadFormat()))
}
if !bytes.Equal(expected.OriginalPayload().AsRaw(), actual.OriginalPayload().AsRaw()) {
errs = multierr.Append(errs, fmt.Errorf("keepFrames does not match expected '%s', actual '%s'", expected.OriginalPayload().AsRaw(), actual.OriginalPayload().AsRaw()))
}
if expected.StartTime() != actual.StartTime() {
errs = multierr.Append(errs, fmt.Errorf("startTime doesn't match expected: %d, actual: %d", expected.StartTime(), actual.StartTime()))
}
if expected.Duration() != actual.Duration() {
errs = multierr.Append(errs, fmt.Errorf("duration doesn't match expected: %d, actual: %d", expected.Duration(), actual.Duration()))
}
if expected.Period() != actual.Period() {
errs = multierr.Append(errs, fmt.Errorf("period does not match expected '%d', actual '%d'", expected.Period(), actual.Period()))
}
if expected.DefaultSampleTypeStrindex() != actual.DefaultSampleTypeStrindex() {
errs = multierr.Append(errs, fmt.Errorf("defaultSampleType does not match expected '%d', actual '%d'", expected.DefaultSampleTypeStrindex(), actual.DefaultSampleTypeStrindex()))
}
if expected.PeriodType().TypeStrindex() != actual.PeriodType().TypeStrindex() ||
expected.PeriodType().UnitStrindex() != actual.PeriodType().UnitStrindex() ||
expected.PeriodType().AggregationTemporality() != actual.PeriodType().AggregationTemporality() {
errs = multierr.Append(errs, fmt.Errorf("periodType does not match expected 'unit: %d, type: %d, aggregationTemporality: %d', actual 'unit: %d, type: %d,"+
"aggregationTemporality: %d'", expected.PeriodType().UnitStrindex(), expected.PeriodType().TypeStrindex(), expected.PeriodType().AggregationTemporality(),
actual.PeriodType().UnitStrindex(), actual.PeriodType().TypeStrindex(), actual.PeriodType().AggregationTemporality()))
}
errs = multierr.Append(errs, internal.AddErrPrefix("sampleType", CompareProfileValueTypeSlice(expected.SampleType(), actual.SampleType())))
errs = multierr.Append(errs, internal.AddErrPrefix("sample", CompareProfileSampleSlice(expected.Sample(), actual.Sample())))
errs = multierr.Append(errs, internal.AddErrPrefix("mapping", CompareProfileMappingSlice(expected.MappingTable(), actual.MappingTable())))
errs = multierr.Append(errs, internal.AddErrPrefix("location", CompareProfileLocationSlice(expected.LocationTable(), actual.LocationTable())))
errs = multierr.Append(errs, internal.AddErrPrefix("function", CompareProfileFunctionSlice(expected.FunctionTable(), actual.FunctionTable())))
errs = multierr.Append(errs, internal.AddErrPrefix("attributeUnits", CompareProfileAttributeUnitSlice(expected.AttributeUnits(), actual.AttributeUnits())))
errs = multierr.Append(errs, internal.AddErrPrefix("linkTable", CompareProfileLinkSlice(expected.LinkTable(), actual.LinkTable())))
return errs
}
func CompareProfileValueTypeSlice(expected, actual pprofile.ValueTypeSlice) error {
var errs error
if expected.Len() != actual.Len() {
errs = multierr.Append(errs, fmt.Errorf("number of valueTypes doesn't match expected: %d, actual: %d",
expected.Len(), actual.Len()))
return errs
}
numValueTypes := expected.Len()
matchingValueTypes := make(map[pprofile.ValueType]pprofile.ValueType, numValueTypes)
var outOfOrderErrs error
for e := 0; e < numValueTypes; e++ {
elr := expected.At(e)
var foundMatch bool
for a := 0; a < numValueTypes; a++ {
alr := actual.At(a)
if _, ok := matchingValueTypes[alr]; ok {
continue
}
if elr.TypeStrindex() == alr.TypeStrindex() && elr.UnitStrindex() == alr.UnitStrindex() {
foundMatch = true
matchingValueTypes[alr] = elr
if e != a {
outOfOrderErrs = multierr.Append(outOfOrderErrs,
fmt.Errorf(`valueTypes are out of order: valueType "unit: %d, type: %d, aggregationTemporality: %d" expected at index %d, found at index %d`,
elr.UnitStrindex(), elr.TypeStrindex(), elr.AggregationTemporality(), e, a))
}
break
}
}
if !foundMatch {
errs = multierr.Append(errs, fmt.Errorf(`missing expected valueType "unit: %d, type: %d, aggregationTemporality: %d"`, elr.UnitStrindex(), elr.TypeStrindex(), elr.AggregationTemporality()))
}
}
for i := 0; i < numValueTypes; i++ {
if _, ok := matchingValueTypes[actual.At(i)]; !ok {
errs = multierr.Append(errs, fmt.Errorf(`unexpected valueType "unit: %d, type: %d, aggregationTemporality: %d"`,
actual.At(i).UnitStrindex(), actual.At(i).TypeStrindex(), actual.At(i).AggregationTemporality()))
}
}
if errs != nil {
return errs
}
if outOfOrderErrs != nil {
return outOfOrderErrs
}
for alr, elr := range matchingValueTypes {
if !isValueTypeEqual(elr, alr) {
errs = multierr.Append(errs, fmt.Errorf(`expected valueType "unit: %d, type: %d, aggregationTemporality: %d",`+
`got "unit: %d, type: %d, aggregationTemporality: %d"`, elr.UnitStrindex(), elr.TypeStrindex(), elr.AggregationTemporality(),
alr.UnitStrindex(), alr.TypeStrindex(), alr.AggregationTemporality()))
}
}
return errs
}
func isValueTypeEqual(expected, actual pprofile.ValueType) bool {
return expected.TypeStrindex() == actual.TypeStrindex() &&
expected.UnitStrindex() == actual.UnitStrindex() &&
expected.AggregationTemporality() == actual.AggregationTemporality()
}
func CompareProfileSampleSlice(expected, actual pprofile.SampleSlice) error {
var errs error
if expected.Len() != actual.Len() {
errs = multierr.Append(errs, fmt.Errorf("number of samples doesn't match expected: %d, actual: %d",
expected.Len(), actual.Len()))
return errs
}
numSlice := expected.Len()
matchingItems := make(map[pprofile.Sample]pprofile.Sample, numSlice)
var outOfOrderErrs error
for e := 0; e < numSlice; e++ {
elr := expected.At(e)
var foundMatch bool
for a := 0; a < numSlice; a++ {
alr := actual.At(a)
if _, ok := matchingItems[alr]; ok {
continue
}
if reflect.DeepEqual(elr.AttributeIndices().AsRaw(), alr.AttributeIndices().AsRaw()) {
foundMatch = true
matchingItems[alr] = elr
if e != a {
outOfOrderErrs = multierr.Append(outOfOrderErrs,
fmt.Errorf(`samples are out of order: sample "attributes: %v" expected at index %d, found at index %d`,
elr.AttributeIndices().AsRaw(), e, a))
}
break
}
}
if !foundMatch {
errs = multierr.Append(errs, fmt.Errorf(`missing expected sample "attributes: %v"`, elr.AttributeIndices().AsRaw()))
}
}
for i := 0; i < numSlice; i++ {
if _, ok := matchingItems[actual.At(i)]; !ok {
errs = multierr.Append(errs, fmt.Errorf(`unexpected sample "attributes: %v"`,
actual.At(i).AttributeIndices().AsRaw()))
}
}
if errs != nil {
return errs
}
if outOfOrderErrs != nil {
return outOfOrderErrs
}
for alr, elr := range matchingItems {
errPrefix := fmt.Sprintf(`sample "attributes: %v"`, elr.AttributeIndices().AsRaw())
errs = multierr.Append(errs, internal.AddErrPrefix(errPrefix, CompareProfileSample(elr, alr)))
}
return errs
}
func CompareProfileSample(expected, actual pprofile.Sample) error {
var errs error
if expected.LocationsStartIndex() != actual.LocationsStartIndex() {
errs = multierr.Append(errs, fmt.Errorf("expected locationStartIndex '%d', got '%d'", expected.LocationsStartIndex(), actual.LocationsStartIndex()))
}
if expected.LocationsLength() != actual.LocationsLength() {
errs = multierr.Append(errs, fmt.Errorf("expected locationLenght '%d', got '%d'", expected.LocationsLength(), actual.LocationsLength()))
}
if !reflect.DeepEqual(expected.TimestampsUnixNano().AsRaw(), actual.TimestampsUnixNano().AsRaw()) {
errs = multierr.Append(errs, fmt.Errorf("expected timestampUnixNano '%v', got '%v'", expected.TimestampsUnixNano().AsRaw(), actual.TimestampsUnixNano().AsRaw()))
}
if !reflect.DeepEqual(expected.Value().AsRaw(), actual.Value().AsRaw()) {
errs = multierr.Append(errs, fmt.Errorf("expected value '%v', got '%v'", expected.Value().AsRaw(), actual.Value().AsRaw()))
}
if !reflect.DeepEqual(expected.TimestampsUnixNano().AsRaw(), actual.TimestampsUnixNano().AsRaw()) {
errs = multierr.Append(errs, fmt.Errorf("expected timestampUnixNano '%v', got '%v'", expected.TimestampsUnixNano().AsRaw(), actual.TimestampsUnixNano().AsRaw()))
}
if !reflect.DeepEqual(expected.AttributeIndices().AsRaw(), actual.AttributeIndices().AsRaw()) {
errs = multierr.Append(errs, fmt.Errorf("expected attributes '%v', got '%v'", expected.AttributeIndices().AsRaw(), actual.AttributeIndices().AsRaw()))
}
return errs
}
func CompareProfileMappingSlice(expected, actual pprofile.MappingSlice) error {
var errs error
if expected.Len() != actual.Len() {
errs = multierr.Append(errs, fmt.Errorf("number of mappings doesn't match expected: %d, actual: %d",
expected.Len(), actual.Len()))
return errs
}
numItems := expected.Len()
matchingItems := make(map[pprofile.Mapping]pprofile.Mapping, numItems)
var outOfOrderErrs error
for e := 0; e < numItems; e++ {
elr := expected.At(e)
var foundMatch bool
for a := 0; a < numItems; a++ {
alr := actual.At(a)
if _, ok := matchingItems[alr]; ok {
continue
}
if reflect.DeepEqual(elr.AttributeIndices().AsRaw(), alr.AttributeIndices().AsRaw()) {
foundMatch = true
matchingItems[alr] = elr
if e != a {
outOfOrderErrs = multierr.Append(outOfOrderErrs,
fmt.Errorf(`mappings are out of order: mapping "attributes: %v" expected at index %d, found at index %d`,
elr.AttributeIndices().AsRaw(), e, a))
}
break
}
}
if !foundMatch {
errs = multierr.Append(errs, fmt.Errorf(`missing expected mapping "attributes: %v"`, elr.AttributeIndices().AsRaw()))
}
}
for i := 0; i < numItems; i++ {
if _, ok := matchingItems[actual.At(i)]; !ok {
errs = multierr.Append(errs, fmt.Errorf(`unexpected profile mapping "attributes: %v"`,
actual.At(i).AttributeIndices().AsRaw()))
}
}
if errs != nil {
return errs
}
if outOfOrderErrs != nil {
return outOfOrderErrs
}
for alr, elr := range matchingItems {
if !isMappingEqual(elr, alr) {
errs = multierr.Append(errs, fmt.Errorf(`mapping with "attributes: %v", does not match expected`,
alr.AttributeIndices().AsRaw()))
}
}
return errs
}
func isMappingEqual(expected, actual pprofile.Mapping) bool {
return expected.MemoryStart() == actual.MemoryStart() &&
expected.MemoryLimit() == actual.MemoryLimit() &&
expected.FileOffset() == actual.FileOffset() &&
expected.FilenameStrindex() == actual.FilenameStrindex() &&
reflect.DeepEqual(expected.AttributeIndices().AsRaw(), actual.AttributeIndices().AsRaw()) &&
expected.HasFunctions() == actual.HasFunctions() &&
expected.HasFilenames() == actual.HasFilenames() &&
expected.HasLineNumbers() == actual.HasLineNumbers() &&
expected.HasInlineFrames() == actual.HasInlineFrames()
}
func CompareProfileFunctionSlice(expected, actual pprofile.FunctionSlice) error {
var errs error
if expected.Len() != actual.Len() {
errs = multierr.Append(errs, fmt.Errorf("number of functions doesn't match expected: %d, actual: %d",
expected.Len(), actual.Len()))
return errs
}
numItems := expected.Len()
matchingItems := make(map[pprofile.Function]pprofile.Function, numItems)
var outOfOrderErrs error
for e := 0; e < numItems; e++ {
elr := expected.At(e)
var foundMatch bool
for a := 0; a < numItems; a++ {
alr := actual.At(a)
if _, ok := matchingItems[alr]; ok {
continue
}
if elr.NameStrindex() == alr.NameStrindex() {
foundMatch = true
matchingItems[alr] = elr
if e != a {
outOfOrderErrs = multierr.Append(outOfOrderErrs,
fmt.Errorf(`functions are out of order: function "name: %d" expected at index %d, found at index %d`,
elr.NameStrindex(), e, a))
}
break
}
}
if !foundMatch {
errs = multierr.Append(errs, fmt.Errorf(`missing expected function "name: %d"`, elr.NameStrindex()))
}
}
for i := 0; i < numItems; i++ {
if _, ok := matchingItems[actual.At(i)]; !ok {
errs = multierr.Append(errs, fmt.Errorf(`unexpected profile function "name: %d"`,
actual.At(i).NameStrindex()))
}
}
if errs != nil {
return errs
}
if outOfOrderErrs != nil {
return outOfOrderErrs
}
for alr, elr := range matchingItems {
if !isFunctionEqual(elr, alr) {
errs = multierr.Append(errs, fmt.Errorf(`function with "name: %d" does not match expected`, alr.NameStrindex()))
}
}
return errs
}
func isFunctionEqual(expected, actual pprofile.Function) bool {
return expected.NameStrindex() == actual.NameStrindex() &&
expected.SystemNameStrindex() == actual.SystemNameStrindex() &&
expected.StartLine() == actual.StartLine() &&
expected.FilenameStrindex() == actual.FilenameStrindex()
}
func CompareProfileLocationSlice(expected, actual pprofile.LocationSlice) error {
var errs error
if expected.Len() != actual.Len() {
errs = multierr.Append(errs, fmt.Errorf("number of locations doesn't match expected: %d, actual: %d",
expected.Len(), actual.Len()))
return errs
}
numItems := expected.Len()
matchingItems := make(map[pprofile.Location]pprofile.Location, numItems)
var outOfOrderErrs error
for e := 0; e < numItems; e++ {
elr := expected.At(e)
var foundMatch bool
for a := 0; a < numItems; a++ {
alr := actual.At(a)
if _, ok := matchingItems[alr]; ok {
continue
}
if reflect.DeepEqual(elr.AttributeIndices().AsRaw(), alr.AttributeIndices().AsRaw()) {
foundMatch = true
matchingItems[alr] = elr
if e != a {
outOfOrderErrs = multierr.Append(outOfOrderErrs,
fmt.Errorf(`locations are out of order: location "attributes: %v" expected at index %d, found at index %d`,
elr.AttributeIndices().AsRaw(), e, a))
}
break
}
}
if !foundMatch {
errs = multierr.Append(errs, fmt.Errorf(`missing expected location "attributes: %v"`, elr.AttributeIndices().AsRaw()))
}
}
for i := 0; i < numItems; i++ {
if _, ok := matchingItems[actual.At(i)]; !ok {
errs = multierr.Append(errs, fmt.Errorf(`unexpected location "attributes: %v"`,
actual.At(i).AttributeIndices().AsRaw()))
}
}
if errs != nil {
return errs
}
if outOfOrderErrs != nil {
return outOfOrderErrs
}
for alr, elr := range matchingItems {
errPrefix := fmt.Sprintf(`location "attributes: %v"`, elr.AttributeIndices().AsRaw())
errs = multierr.Append(errs, internal.AddErrPrefix(errPrefix, CompareProfileLocation(elr, alr)))
}
return errs
}
func CompareProfileLocation(expected, actual pprofile.Location) error {
var errs error
if expected.MappingIndex() != actual.MappingIndex() {
errs = multierr.Append(errs, fmt.Errorf("expected mappingIndex '%d', got '%d'", expected.MappingIndex(), actual.MappingIndex()))
}
if expected.Address() != actual.Address() {
errs = multierr.Append(errs, fmt.Errorf("expected address '%d', got '%d'", expected.Address(), actual.Address()))
}
if expected.IsFolded() != actual.IsFolded() {
errs = multierr.Append(errs, fmt.Errorf("expected isFolded '%v', got '%v'", expected.IsFolded(), actual.IsFolded()))
}
if !reflect.DeepEqual(expected.AttributeIndices().AsRaw(), actual.AttributeIndices().AsRaw()) {
errs = multierr.Append(errs, fmt.Errorf("expected attributes '%v', got '%v'", expected.AttributeIndices().AsRaw(), actual.AttributeIndices().AsRaw()))
}
errPrefix := fmt.Sprintf(`line of location with "attributes: %v"`, expected.AttributeIndices().AsRaw())
errs = multierr.Append(errs, internal.AddErrPrefix(errPrefix, CompareProfileLineSlice(expected.Line(), actual.Line())))
return errs
}
func CompareProfileLineSlice(expected, actual pprofile.LineSlice) error {
var errs error
if expected.Len() != actual.Len() {
errs = multierr.Append(errs, fmt.Errorf("number of lines doesn't match expected: %d, actual: %d",
expected.Len(), actual.Len()))
return errs
}
numItems := expected.Len()
matchingItems := make(map[pprofile.Line]pprofile.Line, numItems)
var outOfOrderErrs error
for e := 0; e < numItems; e++ {
elr := expected.At(e)
var foundMatch bool
for a := 0; a < numItems; a++ {
alr := actual.At(a)
if _, ok := matchingItems[alr]; ok {
continue
}
if elr.FunctionIndex() == alr.FunctionIndex() {
foundMatch = true
matchingItems[alr] = elr
if e != a {
outOfOrderErrs = multierr.Append(outOfOrderErrs,
fmt.Errorf(`lines are out of order: line "functionIndex: %d" expected at index %d, found at index %d`,
elr.FunctionIndex(), e, a))
}
break
}
}
if !foundMatch {
errs = multierr.Append(errs, fmt.Errorf(`missing expected line "functionIndex: %d"`, elr.FunctionIndex()))
}
}
for i := 0; i < numItems; i++ {
if _, ok := matchingItems[actual.At(i)]; !ok {
errs = multierr.Append(errs, fmt.Errorf(`unexpected profile line "functionIndex: %d"`,
actual.At(i).FunctionIndex()))
}
}
if errs != nil {
return errs
}
if outOfOrderErrs != nil {
return outOfOrderErrs
}
for alr, elr := range matchingItems {
if !isLineEqual(elr, alr) {
errs = multierr.Append(errs, fmt.Errorf(`line with "functionIndex: %d" does not match expected`, alr.FunctionIndex()))
}
}
return errs
}
func isLineEqual(expected, actual pprofile.Line) bool {
return expected.FunctionIndex() == actual.FunctionIndex() &&
expected.Line() == actual.Line() &&
expected.Column() == actual.Column()
}
func CompareProfileAttributeUnitSlice(expected, actual pprofile.AttributeUnitSlice) error {
var errs error
if expected.Len() != actual.Len() {
errs = multierr.Append(errs, fmt.Errorf("number of attributeUnits doesn't match expected: %d, actual: %d",
expected.Len(), actual.Len()))
return errs
}
numItems := expected.Len()
matchingItems := make(map[pprofile.AttributeUnit]pprofile.AttributeUnit, numItems)
var outOfOrderErrs error
for e := 0; e < numItems; e++ {
elr := expected.At(e)
var foundMatch bool
for a := 0; a < numItems; a++ {
alr := actual.At(a)
if _, ok := matchingItems[alr]; ok {
continue
}
if elr.AttributeKeyStrindex() == alr.AttributeKeyStrindex() && elr.UnitStrindex() == alr.UnitStrindex() {
foundMatch = true
matchingItems[alr] = elr
if e != a {
outOfOrderErrs = multierr.Append(outOfOrderErrs,
fmt.Errorf(`attributeUnits are out of order: attributeUnit "attributeKey: %d" expected at index %d, found at index %d`,
elr.AttributeKeyStrindex(), e, a))
}
break
}
}
if !foundMatch {
errs = multierr.Append(errs, fmt.Errorf(`missing expected attributeUnit "attributeKey: %d"`, elr.AttributeKeyStrindex()))
}
}
for i := 0; i < numItems; i++ {
if _, ok := matchingItems[actual.At(i)]; !ok {
errs = multierr.Append(errs, fmt.Errorf(`unexpected profile attributeUnit "attributeKey: %d"`,
actual.At(i).AttributeKeyStrindex()))
}
}
if errs != nil {
return errs
}
if outOfOrderErrs != nil {
return outOfOrderErrs
}
return errs
}
func CompareProfileLinkSlice(expected, actual pprofile.LinkSlice) error {
var errs error
if expected.Len() != actual.Len() {
errs = multierr.Append(errs, fmt.Errorf("number of links doesn't match expected: %d, actual: %d",
expected.Len(), actual.Len()))
return errs
}
numItems := expected.Len()
matchingItems := make(map[pprofile.Link]pprofile.Link, numItems)
var outOfOrderErrs error
for e := 0; e < numItems; e++ {
elr := expected.At(e)
var foundMatch bool
for a := 0; a < numItems; a++ {
alr := actual.At(a)
if _, ok := matchingItems[alr]; ok {
continue
}
if elr.TraceID().String() == alr.TraceID().String() && elr.SpanID().String() == alr.SpanID().String() {
foundMatch = true
matchingItems[alr] = elr
if e != a {
outOfOrderErrs = multierr.Append(outOfOrderErrs,
fmt.Errorf(`links are out of order: link "spanId: %s, traceId: %s" expected at index %d, found at index %d`,
elr.SpanID().String(), elr.TraceID().String(), e, a))
}
break
}
}
if !foundMatch {
errs = multierr.Append(errs, fmt.Errorf(`missing expected link "spanId: %s, traceId: %s"`, elr.SpanID().String(), elr.TraceID().String()))
}
}
for i := 0; i < numItems; i++ {
if _, ok := matchingItems[actual.At(i)]; !ok {
errs = multierr.Append(errs, fmt.Errorf(`unexpected profile link "spanId: %s, traceId: %s"`,
actual.At(i).SpanID().String(), actual.At(i).TraceID().String()))
}
}
if errs != nil {
return errs
}
if outOfOrderErrs != nil {
return outOfOrderErrs
}
return errs
}