@@ -372,4 +372,223 @@ mod tests {
372372
373373 assert ! ( !span. span_context( ) . is_sampled( ) ) ;
374374 }
375+
376+ #[ test]
377+ fn in_span_with_context_uses_provided_context ( ) {
378+ use crate :: trace:: { InMemorySpanExporter , SimpleSpanProcessor } ;
379+
380+ let exporter = InMemorySpanExporter :: default ( ) ;
381+ let tracer_provider = crate :: trace:: SdkTracerProvider :: builder ( )
382+ . with_sampler ( Sampler :: AlwaysOn )
383+ . with_span_processor ( SimpleSpanProcessor :: new ( exporter. clone ( ) ) )
384+ . build ( ) ;
385+ let tracer = tracer_provider. tracer ( "test" ) ;
386+
387+ // Create a parent context explicitly
388+ let parent_span = tracer. start ( "parent" ) ;
389+ let parent_trace_id = parent_span. span_context ( ) . trace_id ( ) ;
390+ let parent_span_id = parent_span. span_context ( ) . span_id ( ) ;
391+ let parent_cx = Context :: current_with_span ( parent_span) ;
392+
393+ // Use in_span_with_context with explicit parent context
394+ let mut child_trace_id = None ;
395+ let mut child_span_id = None ;
396+ let mut executed = false ;
397+
398+ let returned_value = tracer. in_span_with_context ( "child-span" , & parent_cx, |cx| {
399+ let span = cx. span ( ) ;
400+ child_trace_id = Some ( span. span_context ( ) . trace_id ( ) ) ;
401+ child_span_id = Some ( span. span_context ( ) . span_id ( ) ) ;
402+ executed = true ;
403+ "test_result"
404+ } ) ;
405+
406+ // Verify child span inherited parent's trace_id
407+ assert_eq ! ( child_trace_id, Some ( parent_trace_id) ) ;
408+ // Verify child has a different span_id than parent
409+ assert_ne ! ( child_span_id, Some ( parent_span_id) ) ;
410+ // Verify the closure was executed
411+ assert ! ( executed) ;
412+ // Verify return value is passed through
413+ assert_eq ! ( returned_value, "test_result" ) ;
414+
415+ // End the parent span to export it
416+ drop ( parent_cx) ;
417+
418+ // Verify parent-child relationship through exporter
419+ let spans = exporter. get_finished_spans ( ) . unwrap ( ) ;
420+ assert_eq ! ( spans. len( ) , 2 ) ;
421+ let parent = spans. iter ( ) . find ( |s| s. name == "parent" ) . unwrap ( ) ;
422+ let child = spans. iter ( ) . find ( |s| s. name == "child-span" ) . unwrap ( ) ;
423+ assert_eq ! ( child. parent_span_id, parent. span_context. span_id( ) ) ;
424+ assert_eq ! (
425+ child. span_context. trace_id( ) ,
426+ parent. span_context. trace_id( )
427+ ) ;
428+ }
429+
430+ #[ test]
431+ fn in_span_with_builder_uses_current_context ( ) {
432+ use crate :: trace:: { InMemorySpanExporter , SimpleSpanProcessor } ;
433+
434+ let exporter = InMemorySpanExporter :: default ( ) ;
435+ let tracer_provider = crate :: trace:: SdkTracerProvider :: builder ( )
436+ . with_sampler ( Sampler :: AlwaysOn )
437+ . with_span_processor ( SimpleSpanProcessor :: new ( exporter. clone ( ) ) )
438+ . build ( ) ;
439+ let tracer = tracer_provider. tracer ( "test" ) ;
440+
441+ // Create a parent span and attach it to the current context
442+ let parent_span = tracer. start ( "parent" ) ;
443+ let parent_trace_id = parent_span. span_context ( ) . trace_id ( ) ;
444+ let parent_span_id = parent_span. span_context ( ) . span_id ( ) ;
445+ let _attached = Context :: current_with_span ( parent_span) . attach ( ) ;
446+
447+ // Use in_span_with_builder with configured span
448+ let mut child_trace_id = None ;
449+
450+ tracer. in_span_with_builder (
451+ tracer
452+ . span_builder ( "child" )
453+ . with_kind ( SpanKind :: Client )
454+ . with_attributes ( vec ! [ KeyValue :: new( "test_key" , "test_value" ) ] ) ,
455+ |cx| {
456+ let span = cx. span ( ) ;
457+ child_trace_id = Some ( span. span_context ( ) . trace_id ( ) ) ;
458+ } ,
459+ ) ;
460+
461+ // Verify child span inherited parent's trace_id
462+ assert_eq ! ( child_trace_id, Some ( parent_trace_id) ) ;
463+
464+ // End the attached context to export the parent span
465+ drop ( _attached) ;
466+
467+ // Verify parent-child relationship through exporter
468+ let spans = exporter. get_finished_spans ( ) . unwrap ( ) ;
469+ assert_eq ! ( spans. len( ) , 2 ) ;
470+ let child = spans. iter ( ) . find ( |s| s. name == "child" ) . unwrap ( ) ;
471+ assert_eq ! ( child. parent_span_id, parent_span_id) ;
472+ assert_eq ! ( child. span_context. trace_id( ) , parent_trace_id) ;
473+ }
474+
475+ #[ test]
476+ fn in_span_with_builder_and_context_uses_provided_context ( ) {
477+ use crate :: trace:: { InMemorySpanExporter , SimpleSpanProcessor } ;
478+
479+ let exporter = InMemorySpanExporter :: default ( ) ;
480+ let tracer_provider = crate :: trace:: SdkTracerProvider :: builder ( )
481+ . with_sampler ( Sampler :: AlwaysOn )
482+ . with_span_processor ( SimpleSpanProcessor :: new ( exporter. clone ( ) ) )
483+ . build ( ) ;
484+ let tracer = tracer_provider. tracer ( "test" ) ;
485+
486+ // Create a parent context explicitly
487+ let parent_span = tracer. start ( "parent" ) ;
488+ let parent_trace_id = parent_span. span_context ( ) . trace_id ( ) ;
489+ let parent_span_id = parent_span. span_context ( ) . span_id ( ) ;
490+ let parent_cx = Context :: current_with_span ( parent_span) ;
491+
492+ // Use in_span_with_builder_and_context with explicit parent context
493+ let mut child_trace_id = None ;
494+ let mut result = 0 ;
495+
496+ let returned_value = tracer. in_span_with_builder_and_context (
497+ tracer
498+ . span_builder ( "child" )
499+ . with_kind ( SpanKind :: Server )
500+ . with_attributes ( vec ! [
501+ KeyValue :: new( "http.method" , "GET" ) ,
502+ KeyValue :: new( "http.url" , "/api/test" ) ,
503+ ] ) ,
504+ & parent_cx,
505+ |cx| {
506+ let span = cx. span ( ) ;
507+ child_trace_id = Some ( span. span_context ( ) . trace_id ( ) ) ;
508+ result = 42 ;
509+ result
510+ } ,
511+ ) ;
512+
513+ // Verify child span inherited parent's trace_id
514+ assert_eq ! ( child_trace_id, Some ( parent_trace_id) ) ;
515+ // Verify return value is passed through
516+ assert_eq ! ( returned_value, 42 ) ;
517+ assert_eq ! ( result, 42 ) ;
518+
519+ // End the parent span to export it
520+ drop ( parent_cx) ;
521+
522+ // Verify parent-child relationship through exporter
523+ let spans = exporter. get_finished_spans ( ) . unwrap ( ) ;
524+ assert_eq ! ( spans. len( ) , 2 ) ;
525+ let child = spans. iter ( ) . find ( |s| s. name == "child" ) . unwrap ( ) ;
526+ assert_eq ! ( child. parent_span_id, parent_span_id) ;
527+ assert_eq ! ( child. span_context. trace_id( ) , parent_trace_id) ;
528+ }
529+
530+ #[ test]
531+ fn in_span_with_builder_and_context_ignores_active_context ( ) {
532+ use crate :: trace:: { InMemorySpanExporter , SimpleSpanProcessor } ;
533+
534+ let exporter = InMemorySpanExporter :: default ( ) ;
535+ let tracer_provider = crate :: trace:: SdkTracerProvider :: builder ( )
536+ . with_sampler ( Sampler :: AlwaysOn )
537+ . with_span_processor ( SimpleSpanProcessor :: new ( exporter. clone ( ) ) )
538+ . build ( ) ;
539+ let tracer = tracer_provider. tracer ( "test" ) ;
540+
541+ // Create an active context with a specific trace context
542+ let active_span_context = SpanContext :: new (
543+ TraceId :: from ( 1u128 ) ,
544+ SpanId :: from ( 1u64 ) ,
545+ TraceFlags :: SAMPLED ,
546+ true ,
547+ Default :: default ( ) ,
548+ ) ;
549+ let active_trace_id = active_span_context. trace_id ( ) ;
550+ let active_span_id = active_span_context. span_id ( ) ;
551+ let _attached = Context :: current_with_span ( TestSpan ( active_span_context) ) . attach ( ) ;
552+
553+ // Create a different parent context with a different trace ID to explicitly provide
554+ let provided_span_context = SpanContext :: new (
555+ TraceId :: from ( 2u128 ) ,
556+ SpanId :: from ( 2u64 ) ,
557+ TraceFlags :: SAMPLED ,
558+ true ,
559+ Default :: default ( ) ,
560+ ) ;
561+ let provided_trace_id = provided_span_context. trace_id ( ) ;
562+ let provided_span_id = provided_span_context. span_id ( ) ;
563+ let provided_cx = Context :: current_with_span ( TestSpan ( provided_span_context) ) ;
564+
565+ // Ensure the two parents have different trace IDs
566+ assert_ne ! ( active_trace_id, provided_trace_id) ;
567+
568+ // Use in_span_with_builder_and_context with explicit parent context
569+ let mut child_trace_id = None ;
570+
571+ tracer. in_span_with_builder_and_context (
572+ tracer. span_builder ( "child" ) . with_kind ( SpanKind :: Internal ) ,
573+ & provided_cx,
574+ |cx| {
575+ let span = cx. span ( ) ;
576+ child_trace_id = Some ( span. span_context ( ) . trace_id ( ) ) ;
577+ } ,
578+ ) ;
579+
580+ // Verify child uses the provided context, NOT the active context
581+ assert_eq ! ( child_trace_id, Some ( provided_trace_id) ) ;
582+ assert_ne ! ( child_trace_id, Some ( active_trace_id) ) ;
583+
584+ // Verify parent-child relationship through exporter
585+ let spans = exporter. get_finished_spans ( ) . unwrap ( ) ;
586+ assert_eq ! ( spans. len( ) , 1 ) ;
587+ let child = & spans[ 0 ] ;
588+ assert_eq ! ( child. name, "child" ) ;
589+ assert_eq ! ( child. parent_span_id, provided_span_id) ;
590+ assert_eq ! ( child. span_context. trace_id( ) , provided_trace_id) ;
591+ assert_ne ! ( child. parent_span_id, active_span_id) ;
592+ assert_ne ! ( child. span_context. trace_id( ) , active_trace_id) ;
593+ }
375594}
0 commit comments