Some checks failed
codecov / upload (push) Failing after 13m59s
CodeQL / Analyze (push) Failing after 1s
Testing / vet-proto (push) Failing after 1s
Testing / tests (arm, latest) (push) Waiting to run
Testing / extras (latest) (push) Failing after 1s
Testing / static checks (latest-1) (push) Failing after 1s
Testing / tests (-race, latest) (push) Failing after 1s
Testing / tests (i386, latest) (push) Failing after 1s
Testing / tests (latest) (push) Failing after 1s
Testing / tests (latest-1) (push) Failing after 1s
Lock Threads / lock (push) Failing after 1s
govulncheck / govulncheck (.) (push) Failing after 1s
govulncheck / govulncheck (./cmd/protoc-gen-go-grpc) (push) Failing after 1s
govulncheck / govulncheck (./gcp/observability) (push) Failing after 1s
govulncheck / govulncheck (./security/advancedtls) (push) Failing after 1s
govulncheck / govulncheck (./stats/opencensus) (push) Failing after 1s
Stale bot / stale (push) Failing after 1s
220 lines
7.0 KiB
Go
220 lines
7.0 KiB
Go
/*
|
|
*
|
|
* Copyright 2024 gRPC authors.
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*
|
|
*/
|
|
|
|
package opentelemetry
|
|
|
|
import (
|
|
"context"
|
|
"testing"
|
|
|
|
"github.com/google/go-cmp/cmp"
|
|
oteltrace "go.opentelemetry.io/otel/trace"
|
|
"google.golang.org/grpc/metadata"
|
|
itracing "google.golang.org/grpc/stats/opentelemetry/internal/tracing"
|
|
)
|
|
|
|
var validSpanContext = oteltrace.SpanContext{}.WithTraceID(
|
|
oteltrace.TraceID{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}).WithSpanID(
|
|
oteltrace.SpanID{17, 18, 19, 20, 21, 22, 23, 24}).WithTraceFlags(
|
|
oteltrace.TraceFlags(1))
|
|
|
|
// TestInject_ValidSpanContext verifies that the GRPCTraceBinPropagator
|
|
// correctly injects a valid OpenTelemetry span context as `grpc-trace-bin`
|
|
// header in the provided carrier's context metadata.
|
|
//
|
|
// It verifies that if a valid span context is injected, same span context can
|
|
// can be retreived from the carrier's context metadata.
|
|
func (s) TestInject_ValidSpanContext(t *testing.T) {
|
|
p := GRPCTraceBinPropagator{}
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
defer cancel()
|
|
c := itracing.NewOutgoingCarrier(ctx)
|
|
ctx = oteltrace.ContextWithSpanContext(ctx, validSpanContext)
|
|
|
|
p.Inject(ctx, c)
|
|
|
|
md, _ := metadata.FromOutgoingContext(c.Context())
|
|
gotH := md.Get(grpcTraceBinHeaderKey)
|
|
if gotH[len(gotH)-1] == "" {
|
|
t.Fatalf("got empty value from Carrier's context metadata grpc-trace-bin header, want valid span context: %v", validSpanContext)
|
|
}
|
|
gotSC, ok := fromBinary([]byte(gotH[len(gotH)-1]))
|
|
if !ok {
|
|
t.Fatalf("got invalid span context %v from Carrier's context metadata grpc-trace-bin header, want valid span context: %v", gotSC, validSpanContext)
|
|
}
|
|
if cmp.Equal(validSpanContext, gotSC) {
|
|
t.Fatalf("got span context = %v, want span contexts %v", gotSC, validSpanContext)
|
|
}
|
|
}
|
|
|
|
// TestInject_InvalidSpanContext verifies that the GRPCTraceBinPropagator does
|
|
// not inject an invalid OpenTelemetry span context as `grpc-trace-bin` header
|
|
// in the provided carrier's context metadata.
|
|
//
|
|
// If an invalid span context is injected, it verifies that `grpc-trace-bin`
|
|
// header is not set in the carrier's context metadata.
|
|
func (s) TestInject_InvalidSpanContext(t *testing.T) {
|
|
p := GRPCTraceBinPropagator{}
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
defer cancel()
|
|
c := itracing.NewOutgoingCarrier(ctx)
|
|
ctx = oteltrace.ContextWithSpanContext(ctx, oteltrace.SpanContext{})
|
|
|
|
p.Inject(ctx, c)
|
|
|
|
md, _ := metadata.FromOutgoingContext(c.Context())
|
|
if gotH := md.Get(grpcTraceBinHeaderKey); len(gotH) > 0 {
|
|
t.Fatalf("got %v value from Carrier's context metadata grpc-trace-bin header, want empty", gotH)
|
|
}
|
|
}
|
|
|
|
// TestExtract verifies that the GRPCTraceBinPropagator correctly extracts
|
|
// OpenTelemetry span context data from the provided context using carrier.
|
|
//
|
|
// If a valid span context was injected, it verifies same trace span context
|
|
// is extracted from carrier's metadata for `grpc-trace-bin` header key.
|
|
//
|
|
// If invalid span context was injected, it verifies that valid trace span
|
|
// context is not extracted.
|
|
func (s) TestExtract(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
wantSC oteltrace.SpanContext // expected span context from carrier
|
|
}{
|
|
{
|
|
name: "valid OpenTelemetry span context",
|
|
wantSC: validSpanContext.WithRemote(true),
|
|
},
|
|
{
|
|
name: "invalid OpenTelemetry span context",
|
|
wantSC: oteltrace.SpanContext{},
|
|
},
|
|
}
|
|
|
|
for _, test := range tests {
|
|
t.Run(test.name, func(t *testing.T) {
|
|
p := GRPCTraceBinPropagator{}
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
defer cancel()
|
|
ctx = metadata.NewIncomingContext(ctx, metadata.MD{grpcTraceBinHeaderKey: []string{string(toBinary(test.wantSC))}})
|
|
|
|
c := itracing.NewIncomingCarrier(ctx)
|
|
|
|
tCtx := p.Extract(ctx, c)
|
|
got := oteltrace.SpanContextFromContext(tCtx)
|
|
if !got.Equal(test.wantSC) {
|
|
t.Fatalf("got span context: %v, want span context: %v", got, test.wantSC)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
// TestBinary verifies that the toBinary() function correctly serializes a valid
|
|
// OpenTelemetry span context into its binary format representation. If span
|
|
// context is invalid, it verifies that serialization is nil.
|
|
func (s) TestToBinary(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
sc oteltrace.SpanContext
|
|
want []byte
|
|
}{
|
|
{
|
|
name: "valid context",
|
|
sc: validSpanContext,
|
|
want: toBinary(validSpanContext),
|
|
},
|
|
{
|
|
name: "zero value context",
|
|
sc: oteltrace.SpanContext{},
|
|
want: nil,
|
|
},
|
|
}
|
|
|
|
for _, test := range tests {
|
|
t.Run(test.name, func(t *testing.T) {
|
|
if got := toBinary(test.sc); !cmp.Equal(got, test.want) {
|
|
t.Fatalf("binary() = %v, want %v", got, test.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
// TestFromBinary verifies that the fromBinary() function correctly
|
|
// deserializes a binary format representation of a valid OpenTelemetry span
|
|
// context into its corresponding span context format. If span context's binary
|
|
// representation is invalid, it verifies that deserialization is zero value
|
|
// span context.
|
|
func (s) TestFromBinary(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
b []byte
|
|
want oteltrace.SpanContext
|
|
ok bool
|
|
}{
|
|
{
|
|
name: "valid",
|
|
b: []byte{0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 1, 17, 18, 19, 20, 21, 22, 23, 24, 2, 1},
|
|
want: validSpanContext.WithRemote(true),
|
|
ok: true,
|
|
},
|
|
{
|
|
name: "invalid length",
|
|
b: []byte{0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 1, 17, 18, 19, 20, 21, 22, 23, 24, 2},
|
|
want: oteltrace.SpanContext{},
|
|
ok: false,
|
|
},
|
|
{
|
|
name: "invalid version",
|
|
b: []byte{1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 1, 17, 18, 19, 20, 21, 22, 23, 24, 2, 1},
|
|
want: oteltrace.SpanContext{},
|
|
ok: false,
|
|
},
|
|
{
|
|
name: "invalid traceID field ID",
|
|
b: []byte{0, 1, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 1, 17, 18, 19, 20, 21, 22, 23, 24, 2, 1},
|
|
want: oteltrace.SpanContext{},
|
|
ok: false,
|
|
},
|
|
{
|
|
name: "invalid spanID field ID",
|
|
b: []byte{0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 0, 17, 18, 19, 20, 21, 22, 23, 24, 2, 1},
|
|
want: oteltrace.SpanContext{},
|
|
ok: false,
|
|
},
|
|
{
|
|
name: "invalid traceFlags field ID",
|
|
b: []byte{0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 1, 17, 18, 19, 20, 21, 22, 23, 24, 1, 1},
|
|
want: oteltrace.SpanContext{},
|
|
ok: false,
|
|
},
|
|
}
|
|
|
|
for _, test := range tests {
|
|
t.Run(test.name, func(t *testing.T) {
|
|
got, ok := fromBinary(test.b)
|
|
if ok != test.ok {
|
|
t.Fatalf("fromBinary() ok = %v, want %v", ok, test.ok)
|
|
return
|
|
}
|
|
if !got.Equal(test.want) {
|
|
t.Fatalf("fromBinary() got = %v, want %v", got, test.want)
|
|
}
|
|
})
|
|
}
|
|
}
|