From 607db85570f7a7ea5fc895d01d4354cc9aecad9a Mon Sep 17 00:00:00 2001 From: Peter Bryant Date: Fri, 23 May 2025 16:35:53 -0500 Subject: [PATCH] bridge/opencensus: add test for OTelSpanContextToOC function (#6813) ## Description Adds tests for the `OTelSpanContextToOC` func in the `opencensus bridge` as requested in issue #6561. ## Changes - Added `TestOTelSpanContextToOC` function with four test cases: - Empty span context conversion - Sampled span context conversion - Not sampled span context conversion - Span context with tracestate conversion ## Testing The test verifies that the following fields are correctly converted: - TraceID - SpanID - TraceOptions (sampled/not sampled) - Tracestate (when present) All existing tests continue to pass. ## Fixes Closes #6561 --------- Co-authored-by: Damien Mathieu <42@dmathieu.com> Co-authored-by: Tyler Yahn --- bridge/opencensus/trace_test.go | 100 ++++++++++++++++++++++++++++++++ 1 file changed, 100 insertions(+) diff --git a/bridge/opencensus/trace_test.go b/bridge/opencensus/trace_test.go index d391aa55c..f1ec18fb4 100644 --- a/bridge/opencensus/trace_test.go +++ b/bridge/opencensus/trace_test.go @@ -5,6 +5,7 @@ package opencensus // import "go.opentelemetry.io/otel/bridge/opencensus" import ( "context" + "strings" "testing" "github.com/stretchr/testify/assert" @@ -44,3 +45,102 @@ func TestOCSpanContextToOTel(t *testing.T) { got := OCSpanContextToOTel(input) assert.Equal(t, want, got) } + +func TestOTelSpanContextToOC(t *testing.T) { + tests := []struct { + name string + input oteltrace.SpanContext + expected octrace.SpanContext + }{ + { + name: "empty span context", + input: oteltrace.SpanContext{}, + expected: octrace.SpanContext{ + TraceID: [16]byte{}, + SpanID: [8]byte{}, + TraceOptions: octrace.TraceOptions(0), + }, + }, + { + name: "sampled span context", + input: oteltrace.NewSpanContext(oteltrace.SpanContextConfig{ + TraceID: oteltrace.TraceID{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}, + SpanID: oteltrace.SpanID{1, 2, 3, 4, 5, 6, 7, 8}, + TraceFlags: oteltrace.FlagsSampled, + }), + expected: octrace.SpanContext{ + TraceID: [16]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}, + SpanID: [8]byte{1, 2, 3, 4, 5, 6, 7, 8}, + TraceOptions: octrace.TraceOptions(1), + }, + }, + { + name: "not sampled span context", + input: oteltrace.NewSpanContext(oteltrace.SpanContextConfig{ + TraceID: oteltrace.TraceID{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}, + SpanID: oteltrace.SpanID{1, 2, 3, 4, 5, 6, 7, 8}, + }), + expected: octrace.SpanContext{ + TraceID: [16]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}, + SpanID: [8]byte{1, 2, 3, 4, 5, 6, 7, 8}, + TraceOptions: octrace.TraceOptions(0), + }, + }, + { + name: "span context with tracestate", + input: func() oteltrace.SpanContext { + ts := oteltrace.TraceState{} + ts, _ = ts.Insert("key1", "value1") + ts, _ = ts.Insert("key2", "value2") + return oteltrace.NewSpanContext(oteltrace.SpanContextConfig{ + TraceID: oteltrace.TraceID{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}, + SpanID: oteltrace.SpanID{1, 2, 3, 4, 5, 6, 7, 8}, + TraceState: ts, + }) + }(), + expected: octrace.SpanContext{ + TraceID: [16]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}, + SpanID: [8]byte{1, 2, 3, 4, 5, 6, 7, 8}, + TraceOptions: octrace.TraceOptions(0), + // Tracestate will be set by the conversion function + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := OTelSpanContextToOC(tt.input) + + assert.Equal(t, tt.expected.TraceID, got.TraceID, "TraceID should be correctly converted") + + assert.Equal(t, tt.expected.SpanID, got.SpanID, "SpanID should be correctly converted") + + assert.Equal(t, tt.expected.TraceOptions, got.TraceOptions, "TraceOptions should be correctly converted") + + // Verify Tracestate is populated when input has tracestate + if tt.input.TraceState().Len() > 0 { + assert.NotNil(t, got.Tracestate, "Tracestate should be populated when input has tracestate") + // Verify the tracestate entries are preserved + expectedTraceState := tt.input.TraceState().String() + gotEntries := got.Tracestate.Entries() + + // Convert entries back to a string representation for comparison + var gotTraceStateEntries []string + for _, entry := range gotEntries { + gotTraceStateEntries = append(gotTraceStateEntries, entry.Key+"="+entry.Value) + } + gotTraceState := "" + if len(gotTraceStateEntries) > 0 { + gotTraceState = strings.Join(gotTraceStateEntries, ",") + } + assert.Equal(t, expectedTraceState, gotTraceState, "Tracestate should preserve entries") + } else { + // For empty tracestate cases, ensure the field is properly handled + if got.Tracestate != nil { + entries := got.Tracestate.Entries() + assert.Empty(t, entries, "Empty tracestate should result in empty entries") + } + } + }) + } +}