From e17d2def0bfce57c6aaeef4d5875b8e82c521b2a Mon Sep 17 00:00:00 2001 From: cirilla-zmh Date: Tue, 3 Dec 2024 15:26:04 +0800 Subject: [PATCH] refactor span verifiers --- go.sum | 6 +- test/kratos/v2.6.3/test_kratos_grpc.go | 37 +- test/kratos/v2.6.3/test_kratos_http.go | 38 +- test/verifier/span_verifier.go | 235 ++++++++++ test/verifier/span_verifier_test.go | 602 +++++++++++++++++++++++++ test/verifier/util.go | 4 + test/verifier/verifier.go | 105 +++-- test/verifier/verifier_test.go | 4 +- 8 files changed, 927 insertions(+), 104 deletions(-) create mode 100644 test/verifier/span_verifier.go create mode 100644 test/verifier/span_verifier_test.go diff --git a/go.sum b/go.sum index a6c544f5..7f90c76c 100644 --- a/go.sum +++ b/go.sum @@ -70,11 +70,9 @@ github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc= github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= -github.com/elastic/elastic-transport-go/v8 v8.0.0-alpha h1:SW9xcMVxx4Nv9oRm5rQxzAMAatwiZV8xROP2a48y45Q= -github.com/elastic/elastic-transport-go/v8 v8.0.0-alpha/go.mod h1:87Tcz8IVNe6rVSLdBux1o/PEItLtyabHU3naC7IoqKI= +github.com/elastic/elastic-transport-go/v8 v8.1.0 h1:NeqEz1ty4RQz+TVbUrpSU7pZ48XkzGWQj02k5koahIE= github.com/elastic/elastic-transport-go/v8 v8.1.0/go.mod h1:87Tcz8IVNe6rVSLdBux1o/PEItLtyabHU3naC7IoqKI= -github.com/elastic/go-elasticsearch/v8 v8.0.0 h1:Hte+pgoEZI88j/sQx7u9vK9SqisvJYkYMmxDnQXiJyM= -github.com/elastic/go-elasticsearch/v8 v8.0.0/go.mod h1:8NCWP26meGbncX+R9sxo2JD8IqBjRTuS7yXMstHpd40= +github.com/elastic/go-elasticsearch/v8 v8.4.0 h1:Rn1mcqaIMcNT43hnx2H62cIFZ+B6mjWtzj85BDKrvCE= github.com/elastic/go-elasticsearch/v8 v8.4.0/go.mod h1:yY52i2Vj0unLz+N3Nwx1gM5LXwoj3h2dgptNGBYkMLA= github.com/envoyproxy/go-control-plane v0.13.0 h1:HzkeUz1Knt+3bK+8LG1bxOO/jzWZmdxpwC51i202les= github.com/envoyproxy/go-control-plane v0.13.0/go.mod h1:GRaKG3dwvFoTg4nj7aXdZnvMg4d7nvT/wl9WgVXn3Q8= diff --git a/test/kratos/v2.6.3/test_kratos_grpc.go b/test/kratos/v2.6.3/test_kratos_grpc.go index 5c7de850..ef0ac7f9 100644 --- a/test/kratos/v2.6.3/test_kratos_grpc.go +++ b/test/kratos/v2.6.3/test_kratos_grpc.go @@ -51,29 +51,18 @@ func main() { fmt.Printf("[grpc] SayHello %+v\n", reply) verifier.WaitAndAssertTraces(func(stubs []tracetest.SpanStubs) { - protocolType := verifier.GetAttribute(stubs[0][2].Attributes, "kratos.protocol.type").AsString() - if protocolType != "grpc" { - panic("protocol type should be grpc, actually got " + protocolType) - } - serviceName := verifier.GetAttribute(stubs[0][2].Attributes, "kratos.service.name").AsString() - if serviceName != "opentelemetry-kratos-server" { - panic("service name should be opentelemetry-kratos-server, actually got " + serviceName) - } - serviceId := verifier.GetAttribute(stubs[0][2].Attributes, "kratos.service.id").AsString() - if serviceId != "opentelemetry-id" { - panic("service id should be opentelemetry-id, actually got " + serviceId) - } - serviceVersion := verifier.GetAttribute(stubs[0][2].Attributes, "kratos.service.version").AsString() - if serviceVersion != "v1" { - panic("service version should be v1, actually got " + serviceVersion) - } - serviceMetaAgent := verifier.GetAttribute(stubs[0][2].Attributes, "kratos.service.meta.agent").AsString() - if serviceMetaAgent != "opentelemetry-go" { - panic("service meta agent should be opentelemetry-go, actually got " + serviceMetaAgent) - } - serviceEndpoint := verifier.GetAttribute(stubs[0][2].Attributes, "kratos.service.endpoint").AsStringSlice() - if !strings.Contains(serviceEndpoint[0], ":9000") || !strings.Contains(serviceEndpoint[1], ":8000") { - panic("service endpoint should be grpc://30.221.144.142:9000 http://30.221.144.142:8000, actually got " + fmt.Sprintf("%v", serviceEndpoint)) - } + verifier.NewSpanVerifier(). + HasStringAttribute("kratos.protocol.type", "grpc"). + HasStringAttribute("kratos.service.name", "opentelemetry-kratos-server"). + HasStringAttribute("kratos.service.id", "opentelemetry-id"). + HasStringAttribute("kratos.service.version", "v1"). + HasStringAttribute("kratos.service.meta.agent", "opentelemetry-go"). + HasItemInStringSliceAttribute("kratos.service.endpoint", 0, func(s string) (bool, string) { + return strings.Contains(s, ":9000"), fmt.Sprintf("First endpoint should be xxx:9000, actual value: %v", s) + }). + HasItemInStringSliceAttribute("kratos.service.endpoint", 1, func(s string) (bool, string) { + return strings.Contains(s, ":8000"), fmt.Sprintf("First endpoint should be xxx:8000, actual value: %v", s) + }). + Verify(stubs[0][2]) }, 1) } diff --git a/test/kratos/v2.6.3/test_kratos_http.go b/test/kratos/v2.6.3/test_kratos_http.go index c790c166..a394b174 100644 --- a/test/kratos/v2.6.3/test_kratos_http.go +++ b/test/kratos/v2.6.3/test_kratos_http.go @@ -41,29 +41,19 @@ func main() { } println() } - protocolType := verifier.GetAttribute(stubs[0][2].Attributes, "kratos.protocol.type").AsString() - if protocolType != "http" { - panic("protocol type should be http, actually got " + protocolType) - } - serviceName := verifier.GetAttribute(stubs[0][2].Attributes, "kratos.service.name").AsString() - if serviceName != "opentelemetry-kratos-server" { - panic("service name should be opentelemetry-kratos-server, actually got " + serviceName) - } - serviceId := verifier.GetAttribute(stubs[0][2].Attributes, "kratos.service.id").AsString() - if serviceId != "opentelemetry-id" { - panic("service id should be opentelemetry-id, actually got " + serviceId) - } - serviceVersion := verifier.GetAttribute(stubs[0][2].Attributes, "kratos.service.version").AsString() - if serviceVersion != "v1" { - panic("service version should be v1, actually got " + serviceVersion) - } - serviceMetaAgent := verifier.GetAttribute(stubs[0][2].Attributes, "kratos.service.meta.agent").AsString() - if serviceMetaAgent != "opentelemetry-go" { - panic("service meta agent should be opentelemetry-go, actually got " + serviceMetaAgent) - } - serviceEndpoint := verifier.GetAttribute(stubs[0][2].Attributes, "kratos.service.endpoint").AsStringSlice() - if !strings.Contains(serviceEndpoint[0], ":9000") || !strings.Contains(serviceEndpoint[1], ":8000") { - panic("service endpoint should be grpc://30.221.144.142:9000 http://30.221.144.142:8000, actually got " + fmt.Sprintf("%v", serviceEndpoint)) - } + + verifier.NewSpanVerifier(). + HasStringAttribute("kratos.protocol.type", "http"). + HasStringAttribute("kratos.service.name", "opentelemetry-kratos-server"). + HasStringAttribute("kratos.service.id", "opentelemetry-id"). + HasStringAttribute("kratos.service.version", "v1"). + HasStringAttribute("kratos.service.meta.agent", "opentelemetry-go"). + HasItemInStringSliceAttribute("kratos.service.endpoint", 0, func(s string) (bool, string) { + return strings.Contains(s, ":9000"), fmt.Sprintf("First endpoint should be xxx:9000, actual value: %v", s) + }). + HasItemInStringSliceAttribute("kratos.service.endpoint", 1, func(s string) (bool, string) { + return strings.Contains(s, ":8000"), fmt.Sprintf("First endpoint should be xxx:8000, actual value: %v", s) + }). + Verify(stubs[0][2]) }, 1) } diff --git a/test/verifier/span_verifier.go b/test/verifier/span_verifier.go new file mode 100644 index 00000000..20f81e33 --- /dev/null +++ b/test/verifier/span_verifier.go @@ -0,0 +1,235 @@ +package verifier + +import ( + "go.opentelemetry.io/otel/sdk/trace/tracetest" + "go.opentelemetry.io/otel/trace" + "sort" + "strings" +) + +type SpanVerifier struct { + verifiers []func(tracetest.SpanStub) + conditionalVerifiers []conditionalVerifier +} + +func NewSpanVerifier() *SpanVerifier { + return &SpanVerifier{ + verifiers: make([]func(tracetest.SpanStub), 0), + } +} + +func (sv *SpanVerifier) Verify(span tracetest.SpanStub) { + for _, verifier := range sv.verifiers { + verifier(span) + } + for _, cv := range sv.conditionalVerifiers { + cv.Verify(span) + } +} + +func (sv *SpanVerifier) HasSpanKind(kind trace.SpanKind) *SpanVerifier { + sv.verifiers = append(sv.verifiers, func(span tracetest.SpanStub) { + Assert(kind == span.SpanKind, "Failed to verify span kind, expect value: %v, actual value: %v", kind, span.SpanKind) + }) + return sv +} + +func (sv *SpanVerifier) HasName(name string) *SpanVerifier { + sv.verifiers = append(sv.verifiers, func(span tracetest.SpanStub) { + Assert(name == span.Name, "Failed to verify span name, expect value: %v, actual value: %v", name, span.Name) + }) + return sv +} + +func (sv *SpanVerifier) HasNoParent() *SpanVerifier { + noopSpanId := trace.SpanID{}.String() + sv.verifiers = append(sv.verifiers, func(span tracetest.SpanStub) { + Assert(span.Parent.SpanID().String() == noopSpanId, "Failed to verify parent span, expect value: %v, actual value: %v", trace.SpanID{}.String(), span.Parent.SpanID().String()) + }) + return sv +} + +func (sv *SpanVerifier) HasParent(parentSpan tracetest.SpanStub) *SpanVerifier { + pTraceId := parentSpan.SpanContext.TraceID().String() + pSpanId := parentSpan.SpanContext.SpanID().String() + sv.verifiers = append(sv.verifiers, func(span tracetest.SpanStub) { + Assert(span.SpanContext.TraceID().String() == pTraceId, "Failed to verify parent trace id, expect value: %v, actual value: %v", pTraceId, span.SpanContext.TraceID().String()) + Assert(span.Parent.SpanID().String() == pSpanId, "Failed to verify parent span id, expect value: %v, actual value: %v", pSpanId, span.Parent.SpanID().String()) + }) + return sv +} + +func (sv *SpanVerifier) HasBoolAttribute(key string, value bool) *SpanVerifier { + sv.verifiers = append(sv.verifiers, func(span tracetest.SpanStub) { + attr := GetAttribute(span.Attributes, key) + Assert(!IsAttributeNoop(attr), "Failed to verify attribute of %v, expect value: %v, actual value: ", key, value) + v := attr.AsBool() + Assert(value == v, "Failed to verify attribute of %v, expect value: %v, actual value: %v", key, value, v) + }) + return sv +} + +func (sv *SpanVerifier) HasInt64Attribute(key string, value int64) *SpanVerifier { + sv.verifiers = append(sv.verifiers, func(span tracetest.SpanStub) { + attr := GetAttribute(span.Attributes, key) + Assert(!IsAttributeNoop(attr), "Failed to verify attribute of %v, expect value: %v, actual value: ", key, value) + v := attr.AsInt64() + Assert(value == v, "Failed to verify attribute of %v, expect value: %v, actual value: %v", key, value, v) + }) + return sv +} + +func (sv *SpanVerifier) HasFloat64Attribute(key string, value float64) *SpanVerifier { + sv.verifiers = append(sv.verifiers, func(span tracetest.SpanStub) { + attr := GetAttribute(span.Attributes, key) + Assert(!IsAttributeNoop(attr), "Failed to verify attribute of %v, expect value: %v, actual value: ", key, value) + v := attr.AsFloat64() + Assert(value == v, "Failed to verify attribute of %v, expect value: %v, actual value: %v", key, value, v) + }) + return sv +} + +func (sv *SpanVerifier) HasStringAttribute(key string, value string) *SpanVerifier { + sv.verifiers = append(sv.verifiers, func(span tracetest.SpanStub) { + attr := GetAttribute(span.Attributes, key) + Assert(!IsAttributeNoop(attr), "Failed to verify attribute of %v, expect value: %v, actual value: ", key, value) + v := attr.AsString() + Assert(value == v, "Failed to verify attribute of %v, expect value: %v, actual value: %v", key, value, v) + }) + return sv +} + +func (sv *SpanVerifier) HasStringAttributeContains(key string, value string) *SpanVerifier { + sv.verifiers = append(sv.verifiers, func(span tracetest.SpanStub) { + attr := GetAttribute(span.Attributes, key) + Assert(!IsAttributeNoop(attr), "Failed to verify attribute of %v, expect value contains: %v, actual value: ", key, value) + v := attr.AsString() + Assert(strings.Contains(v, value), "Failed to verify attribute of %v, expect value contains: %v, actual value: %v", key, value, v) + }) + return sv +} + +func (sv *SpanVerifier) HasBoolSliceAttribute(key string, values []bool, ignoreOrder bool) *SpanVerifier { + sv.verifiers = append(sv.verifiers, func(span tracetest.SpanStub) { + attr := GetAttribute(span.Attributes, key) + Assert(!IsAttributeNoop(attr), "Failed to verify attribute of %v, expect value: %v, actual value: ", key, values) + vs := attr.AsBoolSlice() + Assert(len(values) == len(vs), "Failed to verify attribute of %v, expect length: %v, actual length: %v", key, len(values), len(vs)) + if ignoreOrder { + ac := 0 + ec := 0 + for i, v := range vs { + if v { + ac++ + } + if values[i] { + ec++ + } + } + Assert(ac == ec, "Failed to verify attribute of %v, expect value: %v, actual value: %v", key, values, vs) + } else { + for i, v := range vs { + Assert(values[i] == v, "Failed to verify attribute of %v, expect value: %v, actual value: %v", key, values, vs) + } + } + }) + return sv +} + +func (sv *SpanVerifier) HasInt64SliceAttribute(key string, values []int64, ignoreOrder bool) *SpanVerifier { + sv.verifiers = append(sv.verifiers, func(span tracetest.SpanStub) { + attr := GetAttribute(span.Attributes, key) + Assert(!IsAttributeNoop(attr), "Failed to verify attribute of %v, expect value: %v, actual value: ", key, values) + vs := attr.AsInt64Slice() + Assert(len(values) == len(vs), "Failed to verify attribute of %v, expect length: %v, actual length: %v", key, len(values), len(vs)) + if ignoreOrder { + sort.Slice(values, func(i, j int) bool { + return values[i] < values[j] + }) + sort.Slice(vs, func(i, j int) bool { + return vs[i] < vs[j] + }) + } + for i, v := range vs { + Assert(values[i] == v, "Failed to verify attribute of %v, expect value: %v, actual value: %v", key, values, vs) + } + }) + return sv +} + +func (sv *SpanVerifier) HasFloat64SliceAttribute(key string, values []float64, ignoreOrder bool) *SpanVerifier { + sv.verifiers = append(sv.verifiers, func(span tracetest.SpanStub) { + attr := GetAttribute(span.Attributes, key) + Assert(!IsAttributeNoop(attr), "Failed to verify attribute of %v, expect value: %v, actual value: ", key, values) + vs := attr.AsFloat64Slice() + Assert(len(values) == len(vs), "Failed to verify attribute of %v, expect length: %v, actual length: %v", key, len(values), len(vs)) + if ignoreOrder { + sort.Slice(values, func(i, j int) bool { + return values[i] < values[j] + }) + sort.Slice(vs, func(i, j int) bool { + return vs[i] < vs[j] + }) + } + for i, v := range vs { + Assert(values[i] == v, "Failed to verify attribute of %v, expect value: %v, actual value: %v", key, values, vs) + } + }) + return sv +} + +func (sv *SpanVerifier) HasStringSliceAttribute(key string, values []string, ignoreOrder bool) *SpanVerifier { + sv.verifiers = append(sv.verifiers, func(span tracetest.SpanStub) { + attr := GetAttribute(span.Attributes, key) + Assert(!IsAttributeNoop(attr), "Failed to verify attribute of %v, expect value: %v, actual value: ", key, values) + vs := attr.AsStringSlice() + Assert(len(values) == len(vs), "Failed to verify attribute of %v, expect length: %v, actual length: %v", key, len(values), len(vs)) + if ignoreOrder { + sort.Strings(values) + sort.Strings(vs) + } + for i, v := range vs { + Assert(values[i] == v, "Failed to verify attribute of %v, expect value: %v, actual value: %v", key, values, vs) + } + }) + return sv +} + +func (sv *SpanVerifier) HasItemInStringSliceAttribute(key string, index int, predicate func(string) (bool, string)) *SpanVerifier { + sv.verifiers = append(sv.verifiers, func(span tracetest.SpanStub) { + attr := GetAttribute(span.Attributes, key) + Assert(!IsAttributeNoop(attr), "Failed to verify attribute of %v[%v], actual value: ", key, index) + vs := attr.AsStringSlice() + Assert(len(vs) > index, "Failed to verify attribute of %v[%v], cause index out of bound, actual length: %v", key, index, len(vs)) + result, message := predicate(vs[index]) + Assert(result, message) + }) + return sv +} + +func (sv *SpanVerifier) ConditionalVerifier(predicate func() bool, verifier *SpanVerifier) *SpanVerifier { + sv.conditionalVerifiers = append(sv.conditionalVerifiers, conditionalVerifier{ + predicate: predicate, + SpanVerifier: verifier, + }) + return sv +} + +func (sv *SpanVerifier) Merge(verifier *SpanVerifier) *SpanVerifier { + if verifier != nil { + sv.verifiers = append(sv.verifiers, verifier.verifiers...) + sv.conditionalVerifiers = append(sv.conditionalVerifiers, verifier.conditionalVerifiers...) + } + return sv +} + +type conditionalVerifier struct { + *SpanVerifier + predicate func() bool +} + +func (cv *conditionalVerifier) Verify(span tracetest.SpanStub) { + if cv.predicate() { + cv.SpanVerifier.Verify(span) + } +} diff --git a/test/verifier/span_verifier_test.go b/test/verifier/span_verifier_test.go new file mode 100644 index 00000000..b175bcd2 --- /dev/null +++ b/test/verifier/span_verifier_test.go @@ -0,0 +1,602 @@ +package verifier + +import ( + "fmt" + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/sdk/trace/tracetest" + "go.opentelemetry.io/otel/trace" + "testing" +) + +var ( + // 80f198ee56343ba864fe8b2a57d3eff7 + ValidTraceID = trace.TraceID([16]byte{128, 241, 152, 238, 86, 52, 59, 168, 100, 254, 139, 42, 87, 211, 239, 247}) + // aa0ba902b700f067 + ValidSpanID = trace.SpanID([8]byte{170, 11, 169, 2, 183, 0, 240, 103}) + // 00f067aa0ba902b7 + ValidChildSpanID = trace.SpanID([8]byte{0, 240, 103, 170, 11, 169, 2, 183}) +) + +func TestSpanVerifier_HasSpanKind(t *testing.T) { + span := newSpanStub(nil, "testSpan", trace.SpanKindClient) + + sv := NewSpanVerifier() + verifyVerifier(t, "TestRightSpanKind", func() { + sv.HasSpanKind(trace.SpanKindClient).Verify(span) + }, true) + + sv = NewSpanVerifier() + verifyVerifier(t, "TestWrongSpanKind", func() { + sv.HasSpanKind(trace.SpanKindInternal).Verify(span) + }, false) +} + +func TestSpanVerifier_HasName(t *testing.T) { + span := newSpanStub(nil, "testSpan", trace.SpanKindInternal) + + sv := NewSpanVerifier() + verifyVerifier(t, "TestRightSpanName", func() { + sv.HasName("testSpan").Verify(span) + }, true) + + sv = NewSpanVerifier() + verifyVerifier(t, "TestWrongSpanName", func() { + sv.HasName("wrongSpan").Verify(span) + }, false) +} + +func TestSpanVerifier_HasNoParent(t *testing.T) { + // HasNoParent + sv := NewSpanVerifier() + span := newSpanStub(nil, "testSpan", trace.SpanKindInternal) + + verifyVerifier(t, "TestNoParent", func() { + sv.HasNoParent().Verify(span) + }, true) + + // HasParent + sv = NewSpanVerifier() + parentSpan := newSpanStub(nil, "parentSpan", trace.SpanKindInternal) + span = newSpanStub(&parentSpan, "testSpan", trace.SpanKindInternal) + + verifyVerifier(t, "TestHasParent", func() { + sv.HasNoParent().Verify(span) + }, false) +} + +func TestSpanVerifier_HasParent(t *testing.T) { + // HasParent + sv := NewSpanVerifier() + parentSpan := newSpanStub(nil, "parentSpan", trace.SpanKindInternal) + span := newSpanStub(&parentSpan, "testSpan", trace.SpanKindInternal) + verifyVerifier(t, "TestHasParent", func() { + sv.HasParent(parentSpan).Verify(span) + }, true) + + // HasNoParent + sv = NewSpanVerifier() + span = newSpanStub(nil, "testSpan", trace.SpanKindInternal) + verifyVerifier(t, "TestNoParent", func() { + sv.HasParent(parentSpan).Verify(span) + }, false) +} + +func TestSpanVerifier_HasBoolAttribute(t *testing.T) { + span := newSpanStub( + nil, + "testSpan", + trace.SpanKindInternal, + attribute.Bool("boolKeyTrue", true), + attribute.Bool("boolKeyFalse", false), + ) + + // RightBoolKey + sv := NewSpanVerifier() + verifyVerifier(t, "TestRightBoolKey", func() { + sv.HasBoolAttribute("boolKeyTrue", true). + HasBoolAttribute("boolKeyFalse", false). + Verify(span) + }, true) + + // WrongBoolKey + sv = NewSpanVerifier() + verifyVerifier(t, "TestWrongBoolKey", func() { + sv.HasBoolAttribute("boolKeyTrue", false). + HasBoolAttribute("boolKeyFalse", true). + Verify(span) + }, false) + + // NilBoolKey + sv = NewSpanVerifier() + verifyVerifier(t, "TestNilBoolKey", func() { + sv.HasBoolAttribute("boolKeyOther", false). + Verify(span) + }, false) +} + +func TestSpanVerifier_HasInt64Attribute(t *testing.T) { + span := newSpanStub( + nil, + "testSpan", + trace.SpanKindInternal, + attribute.Int("IntKey", 42), + attribute.Int("IntKey0", 0), + attribute.Int64("Int64Key", 42), + attribute.Int64("Int64Key0", 0), + ) + + // RightInt64Key + sv := NewSpanVerifier() + verifyVerifier(t, "TestRightInt64Key", func() { + sv.HasInt64Attribute("IntKey", 42). + HasInt64Attribute("IntKey0", 0). + HasInt64Attribute("Int64Key", 42). + HasInt64Attribute("Int64Key0", 0). + Verify(span) + }, true) + + // WrongInt64Key + sv = NewSpanVerifier() + verifyVerifier(t, "TestWrongInt64Key", func() { + sv.HasInt64Attribute("IntKey", 0). + HasInt64Attribute("IntKey0", 42). + HasInt64Attribute("Int64Key", 0). + HasInt64Attribute("Int64Key0", 42). + Verify(span) + }, false) + + // NilInt64Key + sv = NewSpanVerifier() + verifyVerifier(t, "TestNilInt64Key", func() { + sv.HasInt64Attribute("Int64KeyOther", 0). + Verify(span) + }, false) +} + +func TestSpanVerifier_HasFloat64Attribute(t *testing.T) { + span := newSpanStub( + nil, + "testSpan", + trace.SpanKindInternal, + attribute.Float64("Float64Key", 42.42), + attribute.Float64("Float64Key0", 0), + ) + + // RightFloat64Key + sv := NewSpanVerifier() + verifyVerifier(t, "TestRightFloat64Key", func() { + sv.HasFloat64Attribute("Float64Key", 42.42). + HasFloat64Attribute("Float64Key0", 0). + Verify(span) + }, true) + + // WrongFloat64Key + sv = NewSpanVerifier() + verifyVerifier(t, "TestWrongFloat64Key", func() { + sv.HasFloat64Attribute("Float64Key", 0). + HasFloat64Attribute("Float64Key0", 42.42). + Verify(span) + }, false) + + // NilFloat64Key + sv = NewSpanVerifier() + verifyVerifier(t, "TestNilFloat64Key", func() { + sv.HasFloat64Attribute("Float64KeyOther", 0). + Verify(span) + }, false) +} + +func TestSpanVerifier_HasStringAttribute(t *testing.T) { + span := newSpanStub( + nil, + "testSpan", + trace.SpanKindInternal, + attribute.String("StringKey", "testValue"), + attribute.String("StringKey0", ""), + ) + + // RightStringKey + sv := NewSpanVerifier() + verifyVerifier(t, "TestRightStringKey", func() { + sv.HasStringAttribute("StringKey", "testValue"). + HasStringAttribute("StringKey0", ""). + Verify(span) + }, true) + + // WrongStringKey + sv = NewSpanVerifier() + verifyVerifier(t, "TestWrongStringKey", func() { + sv.HasStringAttribute("StringKey", ""). + HasStringAttribute("StringKey0", "testValue"). + Verify(span) + }, false) + + // NilStringKey + sv = NewSpanVerifier() + verifyVerifier(t, "TestNilStringKey", func() { + sv.HasStringAttribute("StringKeyOther", ""). + Verify(span) + }, false) +} + +func TestSpanVerifier_HasStringAttributeContains(t *testing.T) { + span := newSpanStub( + nil, + "testSpan", + trace.SpanKindInternal, + attribute.String("StringKey", "mouse|cat|dog"), + attribute.String("StringKey0", ""), + ) + + // RightStringKey + sv := NewSpanVerifier() + verifyVerifier(t, "TestRightStringKey", func() { + sv.HasStringAttributeContains("StringKey", "cat"). + HasStringAttributeContains("StringKey", "mouse"). + HasStringAttribute("StringKey0", ""). + Verify(span) + }, true) + + // WrongStringKey + sv = NewSpanVerifier() + verifyVerifier(t, "TestWrongStringKey", func() { + sv.HasStringAttribute("StringKey", "sun"). + HasStringAttribute("StringKey0", "sun"). + Verify(span) + }, false) + + // NilStringKey + sv = NewSpanVerifier() + verifyVerifier(t, "TestNilStringKey", func() { + sv.HasStringAttribute("StringKeyOther", "sun"). + Verify(span) + }, false) +} + +func TestSpanVerifier_HasBoolSliceAttribute(t *testing.T) { + span := newSpanStub( + nil, + "testSpan", + trace.SpanKindInternal, + attribute.BoolSlice("BoolSliceKey", []bool{true, true, false, true}), + attribute.BoolSlice("BoolSliceKey0", []bool{}), + ) + + // RightBoolSliceKey with order + sv := NewSpanVerifier() + verifyVerifier(t, "TestRightBoolSliceKeyWithOrder", func() { + sv.HasBoolSliceAttribute("BoolSliceKey", []bool{true, true, false, true}, false). + HasBoolSliceAttribute("BoolSliceKey0", []bool{}, false). + Verify(span) + }, true) + + // RightBoolSliceKey without order + sv = NewSpanVerifier() + verifyVerifier(t, "TestRightBoolSliceKeyWithoutOrder", func() { + sv.HasBoolSliceAttribute("BoolSliceKey", []bool{true, true, true, false}, true). + HasBoolSliceAttribute("BoolSliceKey0", []bool{}, true). + Verify(span) + }, true) + + // WrongBoolSliceKey with order + sv = NewSpanVerifier() + verifyVerifier(t, "TestWrongBoolSliceKeyWithOrder", func() { + sv.HasBoolSliceAttribute("BoolSliceKey", []bool{}, false). + HasBoolSliceAttribute("BoolSliceKey0", []bool{true, true, false, true}, false). + Verify(span) + }, false) + + // WrongBoolSliceKey without order + sv = NewSpanVerifier() + verifyVerifier(t, "TestWrongBoolSliceKeyWithoutOrder", func() { + sv.HasBoolSliceAttribute("BoolSliceKey", []bool{}, true). + HasBoolSliceAttribute("BoolSliceKey0", []bool{true, true, true, false}, true). + Verify(span) + }, false) + + // NilBoolSliceKey + sv = NewSpanVerifier() + verifyVerifier(t, "TestNilBoolSliceKey", func() { + sv.HasBoolSliceAttribute("BoolSliceKeyOther", []bool{}, true). + HasBoolSliceAttribute("BoolSliceKeyOther2", []bool{}, false). + Verify(span) + }, false) +} + +func TestSpanVerifier_HasInt64SliceAttribute(t *testing.T) { + span := newSpanStub( + nil, + "testSpan", + trace.SpanKindInternal, + attribute.IntSlice("IntSliceKey", []int{42, 12, 4242}), + attribute.IntSlice("IntSliceKey0", []int{}), + attribute.Int64Slice("Int64SliceKey", []int64{42, 12, 4242}), + attribute.Int64Slice("Int64SliceKey0", []int64{}), + ) + + // RightInt64SliceKey with order + sv := NewSpanVerifier() + verifyVerifier(t, "TestRightInt64SliceKeyWithOrder", func() { + sv.HasInt64SliceAttribute("IntSliceKey", []int64{42, 12, 4242}, false). + HasInt64SliceAttribute("IntSliceKey0", []int64{}, false). + HasInt64SliceAttribute("Int64SliceKey", []int64{42, 12, 4242}, false). + HasInt64SliceAttribute("Int64SliceKey0", []int64{}, false). + Verify(span) + }, true) + + // RightInt64SliceKey without order + sv = NewSpanVerifier() + verifyVerifier(t, "TestRightInt64SliceKeyWithoutOrder", func() { + sv.HasInt64SliceAttribute("IntSliceKey", []int64{4242, 12, 42}, true). + HasInt64SliceAttribute("IntSliceKey0", []int64{}, true). + HasInt64SliceAttribute("Int64SliceKey", []int64{4242, 12, 42}, true). + HasInt64SliceAttribute("Int64SliceKey0", []int64{}, true). + Verify(span) + }, true) + + // WrongInt64SliceKey with order + sv = NewSpanVerifier() + verifyVerifier(t, "TestWrongInt64SliceKeyWithOrder", func() { + sv.HasInt64SliceAttribute("IntSliceKey", []int64{}, false). + HasInt64SliceAttribute("IntSliceKey0", []int64{42, 12, 4242}, false). + HasInt64SliceAttribute("Int64SliceKey", []int64{}, false). + HasInt64SliceAttribute("Int64SliceKey0", []int64{42, 12, 4242}, false). + Verify(span) + }, false) + + // WrongInt64SliceKey without order + sv = NewSpanVerifier() + verifyVerifier(t, "TestWrongInt64SliceKeyWithOrder", func() { + sv.HasInt64SliceAttribute("IntSliceKey", []int64{}, true). + HasInt64SliceAttribute("IntSliceKey0", []int64{4242, 12, 42}, true). + HasInt64SliceAttribute("Int64SliceKey", []int64{}, true). + HasInt64SliceAttribute("Int64SliceKey0", []int64{4242, 12, 42}, true). + Verify(span) + }, false) + + // NilInt64SliceKey + sv = NewSpanVerifier() + verifyVerifier(t, "TestNilInt64SliceKey", func() { + sv.HasInt64SliceAttribute("Int64SliceKeyOther", []int64{}, true). + HasInt64SliceAttribute("Int64SliceKeyOther2", []int64{}, false). + Verify(span) + }, false) +} + +func TestSpanVerifier_HasFloat64SliceAttribute(t *testing.T) { + span := newSpanStub( + nil, + "testSpan", + trace.SpanKindInternal, + attribute.Float64Slice("Float64SliceKey", []float64{12.1, 42.1, -1.2, -98.3}), + attribute.Float64Slice("Float64SliceKey0", []float64{}), + ) + + // RightFloat64SliceKey with order + sv := NewSpanVerifier() + verifyVerifier(t, "TestRightFloat64SliceKeyWithOrder", func() { + sv.HasFloat64SliceAttribute("Float64SliceKey", []float64{12.1, 42.1, -1.2, -98.3}, false). + HasFloat64SliceAttribute("Float64SliceKey0", []float64{}, false). + Verify(span) + }, true) + + // RightFloat64SliceKey without order + sv = NewSpanVerifier() + verifyVerifier(t, "TestRightFloat64SliceKeyWithoutOrder", func() { + sv.HasFloat64SliceAttribute("Float64SliceKey", []float64{-98.3, 42.1, 12.1, -1.2}, true). + HasFloat64SliceAttribute("Float64SliceKey0", []float64{}, true). + Verify(span) + }, true) + + // WrongFloat64SliceKey with order + sv = NewSpanVerifier() + verifyVerifier(t, "TestWrongFloat64SliceKeyWithOrder", func() { + sv.HasFloat64SliceAttribute("Float64SliceKey", []float64{}, false). + HasFloat64SliceAttribute("Float64SliceKey0", []float64{12.1, 42.1, -1.2, -98.3}, false). + Verify(span) + }, false) + + // WrongFloat64SliceKey without order + sv = NewSpanVerifier() + verifyVerifier(t, "TestWrongFloat64SliceKeyWithoutOrder", func() { + sv.HasFloat64SliceAttribute("Float64SliceKey", []float64{}, true). + HasFloat64SliceAttribute("Float64SliceKey0", []float64{-98.3, 42.1, 12.1, -1.2}, true). + Verify(span) + }, false) + + // NilFloat64SliceKey + sv = NewSpanVerifier() + verifyVerifier(t, "TestNilFloat64SliceKey", func() { + sv.HasFloat64SliceAttribute("Float64SliceKeyOther", []float64{}, true). + HasFloat64SliceAttribute("Float64SliceKeyOther2", []float64{}, false). + Verify(span) + }, false) +} + +func TestSpanVerifier_HasStringSliceAttribute(t *testing.T) { + span := newSpanStub( + nil, + "testSpan", + trace.SpanKindInternal, + attribute.StringSlice("StringSliceKey", []string{"w3c", "b3", "jaeger", "opentracing"}), + attribute.StringSlice("StringSliceKey0", []string{}), + ) + + // RightStringSliceKey with order + sv := NewSpanVerifier() + verifyVerifier(t, "TestRightStringSliceKeyWithOrder", func() { + sv.HasStringSliceAttribute("StringSliceKey", []string{"w3c", "b3", "jaeger", "opentracing"}, false). + HasStringSliceAttribute("StringSliceKey0", []string{}, false). + Verify(span) + }, true) + + // RightStringSliceKey without order + sv = NewSpanVerifier() + verifyVerifier(t, "TestRightStringSliceKeyWithoutOrder", func() { + sv.HasStringSliceAttribute("StringSliceKey", []string{"w3c", "opentracing", "jaeger", "b3"}, true). + HasStringSliceAttribute("StringSliceKey0", []string{}, true). + Verify(span) + }, true) + + // WrongStringSliceKey with order + sv = NewSpanVerifier() + verifyVerifier(t, "TestWrongStringSliceKeyWithOrder", func() { + sv.HasStringSliceAttribute("StringSliceKey", []string{}, false). + HasStringSliceAttribute("StringSliceKey0", []string{"w3c", "b3", "jaeger", "opentracing"}, false). + Verify(span) + }, false) + + // WrongStringSliceKey without order + sv = NewSpanVerifier() + verifyVerifier(t, "TestWrongStringSliceKeyWithoutOrder", func() { + sv.HasStringSliceAttribute("StringSliceKey", []string{}, true). + HasStringSliceAttribute("StringSliceKey0", []string{"w3c", "opentracing", "jaeger", "b3"}, true). + Verify(span) + }, false) + + // NilStringSliceKey + sv = NewSpanVerifier() + verifyVerifier(t, "TestNilStringSliceKey", func() { + sv.HasStringSliceAttribute("StringSliceKeyOther", []string{}, true). + HasStringSliceAttribute("StringSliceKeyOther2", []string{}, false). + Verify(span) + }, false) +} + +func TestSpanVerifier_HasItemInStringSliceAttribute(t *testing.T) { + span := newSpanStub( + nil, + "testSpan", + trace.SpanKindInternal, + attribute.StringSlice("StringSliceKey", []string{"w3c", "b3", "jaeger", "opentracing"}), + attribute.StringSlice("StringSliceKey0", []string{}), + ) + + sv := NewSpanVerifier() + verifyVerifier(t, "TestSucc", func() { + sv.HasItemInStringSliceAttribute("StringSliceKey", 0, func(s string) (bool, string) { + return s == "w3c", "" + }). + HasItemInStringSliceAttribute("StringSliceKey", 2, func(s string) (bool, string) { + return s == "jaeger", "" + }). + Verify(span) + }, true) + + sv = NewSpanVerifier() + verifyVerifier(t, "TestFail", func() { + sv.HasItemInStringSliceAttribute("StringSliceKey", 2, func(s string) (bool, string) { + return s == "w3c", "" + }). + HasItemInStringSliceAttribute("StringSliceKey", 0, func(s string) (bool, string) { + return s == "jaeger", "" + }). + Verify(span) + }, false) + + sv = NewSpanVerifier() + verifyVerifier(t, "TestOutOfBound", func() { + sv.HasItemInStringSliceAttribute("StringSliceKey0", 0, func(s string) (bool, string) { + return s == "w3c", "" + }). + Verify(span) + }, false) +} + +func TestSpanVerifier_ConditionalVerifier(t *testing.T) { + var verifyDetail = true + span := newSpanStub( + nil, + "testSpan", + trace.SpanKindInternal, + attribute.String("StringKey", "normal"), + attribute.String("StringDetailKey", "detail"), + ) + + sv := NewSpanVerifier() + verifyVerifier(t, "TestConditionalVerifier", func() { + sv.HasStringAttribute("StringKey", "normal"). + ConditionalVerifier(func() bool { + return verifyDetail + }, NewSpanVerifier().HasStringAttribute("StringDetailKey", "detail")). + Verify(span) + }, true) + + verifyDetail = false + sv = NewSpanVerifier() + verifyVerifier(t, "TestConditionalVerifierIgnore", func() { + sv.HasStringAttribute("StringKey", "normal"). + ConditionalVerifier(func() bool { + return verifyDetail + }, NewSpanVerifier().HasStringAttribute("StringDetailKey2", "detail")). + Verify(span) + }, true) +} + +func TestSpanVerifier_Merge(t *testing.T) { + span := newSpanStub( + nil, + "testSpan", + trace.SpanKindInternal, + attribute.String("StringKey", "normal"), + attribute.String("StringDetailKey", "detail"), + ) + + sv := NewSpanVerifier() + verifyVerifier(t, "TestMergeSuccVerifier", func() { + sv.HasStringAttribute("StringKey", "normal"). + Merge(NewSpanVerifier().HasStringAttribute("StringDetailKey", "detail")). + Verify(span) + }, true) + + sv = NewSpanVerifier() + verifyVerifier(t, "TestMergeFailVerifier", func() { + sv.HasStringAttribute("StringKey", "normal"). + Merge(NewSpanVerifier().HasStringAttribute("StringDetailKey2", "detail")). + Verify(span) + }, false) +} + +func newSpanStub(pSpan *tracetest.SpanStub, name string, kind trace.SpanKind, attrs ...attribute.KeyValue) tracetest.SpanStub { + if pSpan == nil { + return tracetest.SpanStub{ + SpanKind: kind, + Name: name, + Attributes: attrs, + Parent: trace.SpanContext{}, + SpanContext: trace.NewSpanContext(trace.SpanContextConfig{ + TraceID: ValidTraceID, + SpanID: ValidSpanID, + TraceFlags: trace.FlagsSampled, + }), + } + } else { + return tracetest.SpanStub{ + SpanKind: kind, + Name: name, + Attributes: attrs, + Parent: pSpan.SpanContext, + SpanContext: trace.NewSpanContext(trace.SpanContextConfig{ + TraceID: pSpan.SpanContext.TraceID(), + SpanID: ValidChildSpanID, + TraceFlags: pSpan.SpanContext.TraceFlags(), + TraceState: pSpan.SpanContext.TraceState(), + }), + } + } +} + +func verifyVerifier(t *testing.T, testName string, testFunc func(), shouldPass bool) { + defer func() { + var err error + if r := recover(); r != nil { + err = fmt.Errorf("panic: %v", r) + } + if shouldPass { + Assert(err == nil, "Failed to run %v:%v, expect result: SUCCESS, actual: FAILED, cause: %v", t.Name(), testName, err) + } else { + Assert(err != nil, "Failed to run %v:%v, expect result: FAILED, actual: SUCCESS", t.Name(), testName) + } + }() + testFunc() +} diff --git a/test/verifier/util.go b/test/verifier/util.go index eff705ec..7fe6c1a3 100644 --- a/test/verifier/util.go +++ b/test/verifier/util.go @@ -35,6 +35,10 @@ func GetAttribute(attrs []attribute.KeyValue, name string) attribute.Value { return attribute.Value{} } +func IsAttributeNoop(value attribute.Value) bool { + return value.Type() == attribute.INVALID +} + func Assert(cond bool, format string, args ...interface{}) { if !cond { panic(fmt.Sprintf(format, args...)) diff --git a/test/verifier/verifier.go b/test/verifier/verifier.go index b2b5935e..0b922fbe 100644 --- a/test/verifier/verifier.go +++ b/test/verifier/verifier.go @@ -16,42 +16,40 @@ package verifier import ( "go.opentelemetry.io/otel/attribute" - "strings" - "go.opentelemetry.io/otel/sdk/trace/tracetest" "go.opentelemetry.io/otel/trace" ) // VerifyDbAttributes TODO: make attribute name to semconv attribute func VerifyDbAttributes(span tracetest.SpanStub, name, system, address, statement, operation string) { - Assert(span.SpanKind == trace.SpanKindClient, "Expect to be client span, got %d", span.SpanKind) - Assert(span.Name == name, "Except client span name to be %s, got %s", name, span.Name) - actualSystem := GetAttribute(span.Attributes, "db.system").AsString() - Assert(actualSystem == system, "Except client db system to be %s, got %s", system, actualSystem) - actualConnStr := GetAttribute(span.Attributes, "server.address").AsString() - Assert(strings.Contains(actualConnStr, address), "Except client address str to be %s, got %s", address, actualConnStr) - actualStatement := GetAttribute(span.Attributes, "db.query.text").AsString() - Assert(strings.Contains(actualStatement, statement), "Except client db statement to be %s, got %s", statement, actualStatement) - actualOperation := GetAttribute(span.Attributes, "db.operation.name").AsString() - Assert(actualOperation == operation, "Except client db operation to be %s, got %s", operation, actualOperation) + NewSpanVerifier(). + HasSpanKind(trace.SpanKindClient). + HasName(name). + HasStringAttribute("db.system", system). + HasStringAttributeContains("server.address", address). + HasStringAttributeContains("db.query.text", statement). + HasStringAttribute("db.operation.name", operation). + Verify(span) } func VerifyHttpClientAttributes(span tracetest.SpanStub, name, method, fullUrl, protocolName, protocolVersion, networkTransport, networkType, localAddr, peerAddr string, statusCode, localPort, peerPort int64) { - Assert(span.SpanKind == trace.SpanKindClient, "Expect to be client span, got %d", span.SpanKind) - Assert(span.Name == name, "Except client span name to be %s, got %s", name, span.Name) - Assert(GetAttribute(span.Attributes, "http.request.method").AsString() == method, "Except method to be %s, got %s", method, GetAttribute(span.Attributes, "http.request.method").AsString()) - Assert(GetAttribute(span.Attributes, "url.full").AsString() == fullUrl, "Except full url to be %s, got %s", fullUrl, GetAttribute(span.Attributes, "url.full").AsString()) - Assert(GetAttribute(span.Attributes, "network.protocol.name").AsString() == protocolName, "Except protocol name to be %s, got %s", protocolName, GetAttribute(span.Attributes, "network.protocol.name").AsString()) - Assert(GetAttribute(span.Attributes, "network.protocol.version").AsString() == protocolVersion, "Except protocol version to be %s, got %s", protocolVersion, GetAttribute(span.Attributes, "network.protocol.version").AsString()) - Assert(GetAttribute(span.Attributes, "network.transport").AsString() == networkTransport, "Except network transport to be %s, got %s", networkTransport, GetAttribute(span.Attributes, "network.transport").AsString()) - Assert(GetAttribute(span.Attributes, "network.type").AsString() == networkType, "Except network type to be %s, got %s", networkType, GetAttribute(span.Attributes, "network.type").AsString()) - Assert(GetAttribute(span.Attributes, "network.local.address").AsString() == localAddr, "Except local addr to be %s, got %s", localAddr, GetAttribute(span.Attributes, "network.local.address").AsString()) - Assert(GetAttribute(span.Attributes, "network.peer.address").AsString() == peerAddr, "Except peer addr to be %s, got %s", peerAddr, GetAttribute(span.Attributes, "network.peer.address").AsString()) - Assert(GetAttribute(span.Attributes, "http.response.status_code").AsInt64() == statusCode, "Except status code to be %d, got %d", statusCode, GetAttribute(span.Attributes, "http.response.status_code").AsInt64()) - Assert(GetAttribute(span.Attributes, "network.peer.port").AsInt64() == peerPort, "Except peer port to be %d, got %d", peerPort, GetAttribute(span.Attributes, "network.peer.port").AsInt64()) - if localPort > 0 { - Assert(GetAttribute(span.Attributes, "network.local.port").AsInt64() == localPort, "Except local port to be %d, got %d", localPort, GetAttribute(span.Attributes, "network.local.port").AsInt64()) - } + NewSpanVerifier(). + HasSpanKind(trace.SpanKindClient). + HasName(name). + HasStringAttribute("http.request.method", method). + HasStringAttribute("url.full", fullUrl). + HasStringAttribute("network.protocol.name", protocolName). + HasStringAttribute("network.protocol.version", protocolVersion). + HasStringAttribute("network.transport", networkTransport). + HasStringAttribute("network.type", networkType). + HasStringAttribute("network.local.address", localAddr). + HasStringAttribute("network.peer.address", peerAddr). + HasInt64Attribute("http.response.status_code", statusCode). + HasInt64Attribute("network.peer.port", peerPort). + ConditionalVerifier(func() bool { + return localPort > 0 + }, NewSpanVerifier().HasInt64Attribute("network.local.port", localPort)). + Verify(span) } func VerifyHttpClientMetricsAttributes(attrs []attribute.KeyValue, method, serverAddress, errorType, protocolName, protocolVersion string, serverPort, statusCode int) { @@ -65,20 +63,22 @@ func VerifyHttpClientMetricsAttributes(attrs []attribute.KeyValue, method, serve } func VerifyHttpServerAttributes(span tracetest.SpanStub, name, method, protocolName, networkTransport, networkType, localAddr, peerAddr, agent, scheme, path, query, route string, statusCode int64) { - Assert(span.SpanKind == trace.SpanKindServer, "Expect to be client span, got %d", span.SpanKind) - Assert(span.Name == name, "Except client span name to be %s, got %s", name, span.Name) - Assert(GetAttribute(span.Attributes, "http.request.method").AsString() == method, "Except method to be %s, got %s", method, GetAttribute(span.Attributes, "http.request.method").AsString()) - Assert(GetAttribute(span.Attributes, "network.protocol.name").AsString() == protocolName, "Except protocol name to be %s, got %s", protocolName, GetAttribute(span.Attributes, "network.protocol.name").AsString()) - Assert(GetAttribute(span.Attributes, "network.transport").AsString() == networkTransport, "Except network transport to be %s, got %s", networkTransport, GetAttribute(span.Attributes, "network.transport").AsString()) - Assert(GetAttribute(span.Attributes, "network.type").AsString() == networkType, "Except network type to be %s, got %s", networkType, GetAttribute(span.Attributes, "network.type").AsString()) - Assert(GetAttribute(span.Attributes, "network.local.address").AsString() == localAddr, "Except local addr to be %s, got %s", localAddr, GetAttribute(span.Attributes, "network.local.address").AsString()) - Assert(GetAttribute(span.Attributes, "network.peer.address").AsString() == peerAddr, "Except peer addr to be %s, got %s", peerAddr, GetAttribute(span.Attributes, "network.peer.address").AsString()) - Assert(GetAttribute(span.Attributes, "user_agent.original").AsString() == agent, "Except user agent to be %s, got %s", agent, GetAttribute(span.Attributes, "user_agent.original").AsString()) - Assert(GetAttribute(span.Attributes, "url.scheme").AsString() == scheme, "Except url scheme to be %s, got %s", scheme, GetAttribute(span.Attributes, "url.scheme").AsString()) - Assert(GetAttribute(span.Attributes, "url.path").AsString() == path, "Except url path to be %s, got %s", path, GetAttribute(span.Attributes, "url.path").AsString()) - Assert(GetAttribute(span.Attributes, "url.query").AsString() == query, "Except url query to be %s, got %s", query, GetAttribute(span.Attributes, "url.query").AsString()) - Assert(GetAttribute(span.Attributes, "http.route").AsString() == route, "Except http route to be %s, got %s", route, GetAttribute(span.Attributes, "http.route").AsString()) - Assert(GetAttribute(span.Attributes, "http.response.status_code").AsInt64() == statusCode, "Except status code to be %d, got %d", statusCode, GetAttribute(span.Attributes, "http.response.status_code").AsInt64()) + NewSpanVerifier(). + HasSpanKind(trace.SpanKindServer). + HasName(name). + HasStringAttribute("http.request.method", method). + HasStringAttribute("network.protocol.name", protocolName). + HasStringAttribute("network.transport", networkTransport). + HasStringAttribute("network.type", networkType). + HasStringAttribute("network.local.address", localAddr). + HasStringAttribute("network.peer.address", peerAddr). + HasStringAttribute("user_agent.original", agent). + HasStringAttribute("url.scheme", scheme). + HasStringAttribute("url.path", path). + HasStringAttribute("url.query", query). + HasStringAttribute("http.route", route). + HasInt64Attribute("http.response.status_code", statusCode). + Verify(span) } func VerifyHttpServerMetricsAttributes(attrs []attribute.KeyValue, method, httpRoute, errorType, protocolName, protocolVersion, urlScheme string, statusCode int) { @@ -92,18 +92,23 @@ func VerifyHttpServerMetricsAttributes(attrs []attribute.KeyValue, method, httpR } func VerifyRpcServerAttributes(span tracetest.SpanStub, name, system, service, method string) { - Assert(span.SpanKind == trace.SpanKindServer, "Expect to be server span, got %d", span.SpanKind) - verifyRpcAttributes(span, name, system, service, method) + NewSpanVerifier(). + HasSpanKind(trace.SpanKindServer). + Merge(newRpcSpanVerifier(name, system, service, method)). + Verify(span) } func VerifyRpcClientAttributes(span tracetest.SpanStub, name, system, service, method string) { - Assert(span.SpanKind == trace.SpanKindClient, "Expect to be client span, got %d", span.SpanKind) - verifyRpcAttributes(span, name, system, service, method) + NewSpanVerifier(). + HasSpanKind(trace.SpanKindServer). + Merge(newRpcSpanVerifier(name, system, service, method)). + Verify(span) } -func verifyRpcAttributes(span tracetest.SpanStub, name, system, service, method string) { - Assert(span.Name == name, "Except client span name to be %s, got %s", name, span.Name) - Assert(GetAttribute(span.Attributes, "rpc.system").AsString() == system, "Except rpc system to be %s, got %s", method, GetAttribute(span.Attributes, "rpc.system").AsString()) - Assert(GetAttribute(span.Attributes, "rpc.service").AsString() == service, "Except rpc service to be %s, got %s", method, GetAttribute(span.Attributes, "rpc.service").AsString()) - Assert(GetAttribute(span.Attributes, "rpc.method").AsString() == method, "Except rpc method to be %s, got %s", method, GetAttribute(span.Attributes, "rpc.method").AsString()) +func newRpcSpanVerifier(name, system, service, method string) *SpanVerifier { + return NewSpanVerifier(). + HasName(name). + HasStringAttribute("rpc.system", system). + HasStringAttribute("rpc.service", service). + HasStringAttribute("rpc.method", method) } diff --git a/test/verifier/verifier_test.go b/test/verifier/verifier_test.go index 617906d2..1befe349 100644 --- a/test/verifier/verifier_test.go +++ b/test/verifier/verifier_test.go @@ -31,7 +31,7 @@ func TestNoSqlAttributesPass(t *testing.T) { {Key: semconv.DBConnectionStringKey, Value: attribute.StringValue("connString")}, {Key: semconv.DBStatementKey, Value: attribute.StringValue("statement")}, {Key: semconv.DBOperationKey, Value: attribute.StringValue("operation")}, - }}, "name", "dbname", "system", "user", "connString", "statement", "operation") + }}, "name", "system", "connString", "statement", "operation") } func TestNoSqlAttributesFail(t *testing.T) { @@ -51,5 +51,5 @@ func TestNoSqlAttributesFail(t *testing.T) { {Key: semconv.DBConnectionStringKey, Value: attribute.StringValue("connString")}, {Key: semconv.DBStatementKey, Value: attribute.StringValue("wrong statement")}, {Key: semconv.DBOperationKey, Value: attribute.StringValue("operation")}, - }}, "name", "dbname", "system", "user", "connString", "statement", "operation") + }}, "name", "system", "connString", "statement", "operation") }