@@ -62,6 +62,9 @@ func Test_OpenTelemetryRuntime_submit_nilAuthInfo(t *testing.T) {
6262}
6363
6464func Test_OpenTelemetryRuntime_submit_nilContext (t * testing.T ) {
65+ // With op.Context nil, Submit now defaults to context.Background()
66+ // and still produces a span (under the modern SubmitContext path).
67+ // Previously this case skipped tracing entirely.
6568 exporter := tracetest .NewInMemoryExporter ()
6669
6770 tp := tracesdk .NewTracerProvider (
@@ -77,7 +80,7 @@ func Test_OpenTelemetryRuntime_submit_nilContext(t *testing.T) {
7780 operation := testOperation (ctx )
7881 operation .Context = nil
7982
80- assertOpenTelemetrySubmit (t , operation , exporter , 0 ) // just don't panic
83+ assertOpenTelemetrySubmit (t , operation , exporter , 1 )
8184}
8285
8386func Test_injectOpenTelemetrySpanContext (t * testing.T ) {
@@ -106,6 +109,72 @@ func Test_injectOpenTelemetrySpanContext(t *testing.T) {
106109 assert .Len (t , header , 1 )
107110}
108111
112+ // Test_OpenTelemetryRuntime_submitContext exercises the modern
113+ // SubmitContext entry point with a wrapped transport that satisfies
114+ // [ContextualTransport]. The wrapper must forward the explicit ctx
115+ // via the wrapped transport's SubmitContext (not via the legacy
116+ // op.Context field).
117+ func Test_OpenTelemetryRuntime_submitContext (t * testing.T ) {
118+ exporter := tracetest .NewInMemoryExporter ()
119+ tp := tracesdk .NewTracerProvider (
120+ tracesdk .WithSampler (tracesdk .AlwaysSample ()),
121+ tracesdk .WithSyncer (exporter ),
122+ )
123+ otel .SetTracerProvider (tp )
124+
125+ tracer := tp .Tracer ("go-runtime" )
126+ ctx , span := tracer .Start (context .Background (), "op" )
127+ defer span .End ()
128+
129+ header := map [string ][]string {}
130+ mock := & mockContextualRuntime {mockRuntime : mockRuntime {req : runtime.TestClientRequest {Headers : header }}}
131+ tr := newOpenTelemetryTransport (mock , "remote_host" , nil )
132+
133+ // Sentinel in op.Context: the SubmitContext path must ignore
134+ // it (no read for tracing, no mutation) and forward `ctx` instead.
135+ type sentinelKey struct {}
136+ staleCtx := context .WithValue (context .Background (), sentinelKey {}, "stale" )
137+ op := testOperation (staleCtx )
138+ _ , err := tr .SubmitContext (ctx , op )
139+ require .NoError (t , err )
140+
141+ assert .EqualT (t , 1 , mock .submitContextCalls , "wrapper must call SubmitContext on a ContextualTransport" )
142+ assert .EqualT (t , 0 , mock .submitCalls , "legacy Submit must not be called when SubmitContext is available" )
143+ assert .Equal (t , ctx , mock .lastSubmitCtx , "ctx must be forwarded verbatim" )
144+ assert .Equal (t , staleCtx , mock .lastOpCtx , "op.Context must not be mutated under the SubmitContext path" )
145+ assert .Len (t , exporter .GetSpans (), 1 )
146+ }
147+
148+ // Test_OpenTelemetryRuntime_submitContext_legacyFallback verifies the
149+ // fallback path when the wrapped transport implements only the legacy
150+ // Submit method: the wrapper stamps ctx onto op.Context for the call
151+ // and restores the prior value afterwards.
152+ func Test_OpenTelemetryRuntime_submitContext_legacyFallback (t * testing.T ) {
153+ exporter := tracetest .NewInMemoryExporter ()
154+ tp := tracesdk .NewTracerProvider (
155+ tracesdk .WithSampler (tracesdk .AlwaysSample ()),
156+ tracesdk .WithSyncer (exporter ),
157+ )
158+ otel .SetTracerProvider (tp )
159+
160+ tracer := tp .Tracer ("go-runtime" )
161+ ctx , span := tracer .Start (context .Background (), "op" )
162+ defer span .End ()
163+
164+ header := map [string ][]string {}
165+ mock := & mockRuntime {req : runtime.TestClientRequest {Headers : header }}
166+ tr := newOpenTelemetryTransport (mock , "remote_host" , nil )
167+
168+ prevCtx , prevSpan := tracer .Start (context .Background (), "prev" )
169+ defer prevSpan .End ()
170+ op := testOperation (prevCtx )
171+ _ , err := tr .SubmitContext (ctx , op )
172+ require .NoError (t , err )
173+
174+ assert .Equal (t , prevCtx , op .Context , "op.Context must be restored after the wrapped Submit returns" )
175+ assert .Len (t , exporter .GetSpans (), 1 )
176+ }
177+
109178func assertOpenTelemetrySubmit (t * testing.T , operation * runtime.ClientOperation , exporter * tracetest.InMemoryExporter , expectedSpanCount int ) {
110179 header := map [string ][]string {}
111180 tr := newOpenTelemetryTransport (& mockRuntime {runtime.TestClientRequest {Headers : header }}, "remote_host" , nil )
0 commit comments